Hibernate - 每个操作的 ThreadLocal<EntityManager> 与 EntityManager

Hibernate - ThreadLocal<EntityManager> vs EntityManager per operation

我使用 Hibernate 5.1。0.Final、Guice、Jersey。我有创建 EntityManagerFactory 并管理 EntityManager 个实例的 HibernateModule:

public class HibernateModule extends AbstractModule {

    private static final ThreadLocal<EntityManager> ENTITY_MANAGER_CACHE = new ThreadLocal<EntityManager>();

    @Provides @Singleton
    public EntityManagerFactory provideEntityManagerFactory(@Named("hibernate.connection.url") String url, 
        @Named("hibernate.connection.username") String userName, 
        @Named("hibernate.connection.password") String password,
        @Named("hibernate.hbm2ddl.auto") String hbm2ddlAuto,
        @Named("hibernate.show_sql") String showSql) {

        Map<String, String> properties = new HashMap<String, String>();
        properties.put("hibernate.connection.driver_class", "org.postgresql.Driver");
        properties.put("hibernate.connection.url", url);
        properties.put("hibernate.connection.username", userName);
        properties.put("hibernate.connection.password", password);
        properties.put("hibernate.connection.pool_size", "1");
        properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        properties.put("hibernate.hbm2ddl.auto", hbm2ddlAuto);
        properties.put("hibernate.show_sql", showSql);
        properties.put("hibernate.cache.use.query_cache", "false");
        properties.put("hibernate.cache.use_second_level_cache", "false");

        return Persistence.createEntityManagerFactory("db-manager", properties);
    }

    @Provides
    public EntityManager provideEntityManager(EntityManagerFactory entityManagerFactory) {

        EntityManager entityManager = ENTITY_MANAGER_CACHE.get();

        if (entityManager == null || !entityManager.isOpen()) 
            ENTITY_MANAGER_CACHE.set(entityManager = entityManagerFactory.createEntityManager());

        entityManager.clear();

        return entityManager;
    }
}

entityManager.clear() 用于清除持久性上下文并强制从数据库查询最新数据。 GenericDAO 从 HibernateModule 接收注入 EntityManager。主要方法:

public class GenericDAOImpl<T> implements GenericDAO<T> {

    @Inject
    protected EntityManager entityManager;

    private Class<T> type;

    public GenericDAOImpl(){}

    public GenericDAOImpl(Class<T> type) {
        this.type = type;
    }

    @Override
    public void save(T entity) {
        entityManager.getTransaction().begin();
        entityManager.persist(entity);
        entityManager.getTransaction().commit();
    }

    @Override
    public T find(Long entityId) {
        return (T) entityManager.find(type, entityId);
    }
}

以前我曾尝试实施一个解决方案,该解决方案为每个数据库操作提供新的 EntityManager,但它会导致一些副作用,例如 "detached entity passed to persist"。

重用 ThreadLocal<EntityManager> 中的 EntityManager 是好的做法吗?这种实施有什么潜在的缺点吗?

它应该可以正常工作。 Spring 框架正在使用 ThreadLocal class 作为 EntityManager。来自参考:

Spring makes it easy to create and bind a Session to the current thread transparently

如果您想重新使用 EntityManager 实例,您应该记住 JPA 提示,PersistenceContextTypeFlushModeType