or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

exception-translation.mdhibernate-configuration.mdhibernate-transaction-management.mdindex.mdjpa-configuration.mdjpa-transaction-management.mdjpa-vendor-adapters.mdpersistence-unit-management.mdshared-resources.mdutility-classes.mdweb-integration.md
tile.json

utility-classes.mddocs/

Utility Classes

Helper utilities for EntityManager/Session management, JDBC connection access, and transaction timeout configuration.

EntityManagerFactoryUtils

Core utility class for JPA EntityManager handling and exception translation.

Finding EntityManagerFactory

@Service
public class DynamicEntityManagerService {

    @Autowired
    private BeanFactory beanFactory;

    public void processWithDynamicPU(String persistenceUnitName) {
        EntityManagerFactory emf =
            EntityManagerFactoryUtils.findEntityManagerFactory(
                (ListableBeanFactory) beanFactory,
                persistenceUnitName
            );

        EntityManager em =
            EntityManagerFactoryUtils.getTransactionalEntityManager(emf);

        // Use EntityManager
    }
}

Applying Transaction Timeout to Queries

@Service
@Transactional(timeout = 30)
public class ReportService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    public List<Report> generateComplexReport() {
        EntityManager em =
            EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);

        TypedQuery<Report> query = em.createQuery(
            "SELECT r FROM Report r WHERE r.complex = true",
            Report.class
        );

        // Apply current transaction timeout to the query
        EntityManagerFactoryUtils.applyTransactionTimeout(query, entityManagerFactory);

        return query.getResultList();
    }
}

Exception Translation

public class CustomDataAccessor {

    private EntityManager entityManager;

    public User findUser(Long id) {
        try {
            return entityManager.find(User.class, id);
        } catch (RuntimeException ex) {
            DataAccessException dae =
                EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex);
            if (dae != null) {
                throw dae;
            }
            throw ex;
        }
    }
}

Programmatic EntityManager Management

@Service
public class BatchProcessingService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    public void processBatch() {
        EntityManager em = null;
        try {
            em = EntityManagerFactoryUtils.getTransactionalEntityManager(
                entityManagerFactory
            );

            // Process batch
            for (int i = 0; i < 1000; i++) {
                Entity entity = new Entity();
                em.persist(entity);

                if (i % 100 == 0) {
                    em.flush();
                    em.clear();
                }
            }
        } finally {
            if (em != null) {
                EntityManagerFactoryUtils.closeEntityManager(em);
            }
        }
    }
}

Transactional EntityManager Usage

@Service
public class TransactionalService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Transactional
    public void performTransactionalWork() {
        // Get EntityManager bound to current transaction
        EntityManager em =
            EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);

        // All operations participate in same transaction
        User user = new User();
        em.persist(user);

        Order order = new Order();
        order.setUser(user);
        em.persist(order);

        // Changes flushed and committed when transaction completes
    }

    @Transactional(readOnly = true)
    public List<User> readOnlyQuery() {
        EntityManager em =
            EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);

        // EntityManager configured for read-only mode
        return em.createQuery("SELECT u FROM User u", User.class)
            .getResultList();
    }
}

EntityManager with Custom Properties

@Service
public class CustomPropertyService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Transactional
    public User findWithHints(Long id) {
        Map<String, Object> properties = new HashMap<>();
        properties.put("jakarta.persistence.cache.retrieveMode",
            CacheRetrieveMode.BYPASS);
        properties.put("jakarta.persistence.cache.storeMode",
            CacheStoreMode.REFRESH);

        EntityManager em =
            EntityManagerFactoryUtils.getTransactionalEntityManager(
                entityManagerFactory, properties
            );

        return em.find(User.class, id);
    }
}

API Reference

EntityManagerFactoryUtils

abstract class EntityManagerFactoryUtils {

    // Constant
    int ENTITY_MANAGER_SYNCHRONIZATION_ORDER;

    // Find EntityManagerFactory
    static EntityManagerFactory findEntityManagerFactory(
        ListableBeanFactory beanFactory,
        String unitName
    );

    // Obtain transactional EntityManager
    static EntityManager getTransactionalEntityManager(EntityManagerFactory emf);

    static EntityManager getTransactionalEntityManager(
        EntityManagerFactory emf,
        Map<?, ?> properties
    );

    static EntityManager doGetTransactionalEntityManager(
        EntityManagerFactory emf,
        Map<?, ?> properties
    );

    static EntityManager doGetTransactionalEntityManager(
        EntityManagerFactory emf,
        Map<?, ?> properties,
        boolean synchronizedWithTransaction
    );

    // Apply transaction timeout
    static void applyTransactionTimeout(Query query, EntityManagerFactory emf);

    // Exception translation
    static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex);

    // Close EntityManager
    static void closeEntityManager(EntityManager em);
}

SpringBeanContainer

Spring-based implementation of Hibernate's ManagedBeanRegistry for bean management:

@Configuration
public class HibernateConfig {

    @Bean
    public LocalSessionFactoryBean sessionFactory(
            DataSource dataSource,
            ConfigurableListableBeanFactory beanFactory) {

        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setPackagesToScan("com.example.domain");

        Properties properties = new Properties();
        properties.put("hibernate.dialect",
            "org.hibernate.dialect.PostgreSQLDialect");

        // Configure Spring bean container for Hibernate
        properties.put("hibernate.resource.beans.container",
            new SpringBeanContainer(beanFactory));

        sessionFactory.setHibernateProperties(properties);

        return sessionFactory;
    }
}

API Reference

class SpringBeanContainer implements ManagedBeanRegistry {

    // Constructor
    SpringBeanContainer(ConfigurableListableBeanFactory beanFactory);
}

Connection Access

Accessing underlying JDBC Connection through EntityManager:

@Service
public class JdbcOperationsService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Transactional
    public void performJdbcOperation() {
        EntityManager em =
            EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);

        // Unwrap to Hibernate Session (if using Hibernate)
        Session session = em.unwrap(Session.class);

        // Execute work with JDBC Connection
        session.doWork(connection -> {
            try (PreparedStatement ps = connection.prepareStatement(
                    "UPDATE users SET last_login = ? WHERE id = ?")) {
                ps.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
                ps.setLong(2, 123L);
                ps.executeUpdate();
            }
        });
    }
}

Thread Safety

EntityManagerFactoryUtils methods are thread-safe:

  • getTransactionalEntityManager() returns EntityManager bound to current thread's transaction
  • Multiple calls in same transaction return same EntityManager instance
  • EntityManager automatically closed when transaction completes
@Service
public class ConcurrentService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Transactional
    public void processInTransaction() {
        // All these calls return the same EntityManager instance
        EntityManager em1 =
            EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
        EntityManager em2 =
            EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);

        assert em1 == em2;  // Same instance within transaction
    }
}

Related Topics

  • JPA Transaction Management - Transaction configuration
  • Exception Translation - DataAccessException hierarchy