import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityTransaction; import jakarta.persistence.Persistence; import java.util.function.Function; /** * A singleton implementation that encapsulates the JPA logic. * You can configure the database connection in the * {@link /src/main/resources/META-INF/persistence.xml} file. */ public class JpaService { private static JpaService instance; private EntityManagerFactory entityManagerFactory; private JpaService() { entityManagerFactory = Persistence.createEntityManagerFactory("jpa-hibernate-notenmanager"); } public static synchronized JpaService getInstance() { return instance == null ? instance = new JpaService() : instance; } public void closeResource() { if(entityManagerFactory != null) { entityManagerFactory.close(); } } public EntityManagerFactory getEntityManagerFactory() { return entityManagerFactory; } /** * Runs the specified function inside a transaction boundary. The function has * access to a ready to use {@link EntityManager} and can return any type of * value ({@code T}). * * @param function The function to run. * @param <T> The function's return type. * @return the value returned by the specified function. */ public <T> T runInTransaction(Function <EntityManager, T> function) { EntityManager entityManager = entityManagerFactory.createEntityManager(); EntityTransaction entityTransaction = entityManager.getTransaction(); boolean isPersisted = false; entityTransaction.begin(); try { T returnValue = function.apply(entityManager); isPersisted = true; return returnValue; } finally { if(isPersisted) { entityTransaction.commit(); } else { entityTransaction.rollback(); } } } }