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 提示,PersistenceContextType
和 FlushModeType
。
我使用 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 提示,PersistenceContextType
和 FlushModeType
。