Answers:
首选EntityManagerFactory
和EntityManager
。它们由JPA标准定义。
SessionFactory
并且Session
是休眠专用的。该EntityManager
调用引擎盖下Hibernate的Session。并且,如果您需要某些某些特定功能,这些功能在中不可用,则EntityManager
可以通过调用以下内容来获取会话:
Session session = entityManager.unwrap(Session.class);
Session
从EntityManager
,一样SessionFactory.getCurrentSession()
?我的意思是,Session
如果尚未创建,它将打开新的吗?它在多线程环境中如何工作?
我想补充一点,您还可以通过getDelegate()
从调用方法来获取Hibernate的会话EntityManager
。
例如:
Session session = (Session) entityManager.getDelegate();
与相比,我更喜欢JPA2 EntityManager
API SessionFactory
,因为它感觉更现代。一个简单的例子:
JPA:
@PersistenceContext
EntityManager entityManager;
public List<MyEntity> findSomeApples() {
return entityManager
.createQuery("from MyEntity where apples=7", MyEntity.class)
.getResultList();
}
SessionFactory:
@Autowired
SessionFactory sessionFactory;
public List<MyEntity> findSomeApples() {
Session session = sessionFactory.getCurrentSession();
List<?> result = session.createQuery("from MyEntity where apples=7")
.list();
@SuppressWarnings("unchecked")
List<MyEntity> resultCasted = (List<MyEntity>) result;
return resultCasted;
}
我认为很明显,第一个看起来更干净并且也更易于测试,因为EntityManager可以轻松模拟。
return sessionFactory.getCurrentSession().createQuery("from User where id=1").list()
使用EntityManagerFactory方法可以使我们无需额外配置即可使用@ PrePersist,@ PostPersist,@ PreUpdate等回调方法注释。
在使用SessionFactory时使用类似的回调将需要额外的精力。
SessionFactory
与 EntityManagerFactory
正如我在《Hibernate用户指南》中所解释的那样,Hibernate SessionFactory
扩展了JPA EntityManagerFactory
,如下图所示:
因此,SessionFactory
也是JPA EntityManagerFactory
。
无论是SessionFactory
与EntityManagerFactory
包含实体映射元数据,并允许您创建一个Hibernate Session
或EntityManager
。
Session
与 EntityManager
就像SessionFactory
and一样EntityManagerFactory
,Hibernate Session
扩展了JPA EntityManager
。因此,EntityManager
Hibernate中提供了由定义的所有方法Session
。
在Session
和`EntityManager的翻译实体状态转换成SQL语句,如SELECT,INSERT,UPDATE和DELETE。
自举JPA或Hibernate应用程序时,有两种选择:
SessionFactory
通过创建一个BootstrapServiceRegistryBuilder
。如果您使用的是Spring,则Hibernate引导程序将通过来完成LocalSessionFactoryBean
,如GitHub示例所示。EntityManagerFactory
通过Persistence
类或来创建JPA EntityManagerFactoryBuilder
。如果您使用的是Spring,则JPA引导程序通过来完成LocalContainerEntityManagerFactoryBean
,如GitHub示例所示。首选通过JPA引导。这是因为JPA FlushModeType.AUTO
比旧版更好FlushMode.AUTO
,因为它破坏了本机SQL查询的读写一致性。
另外,如果您通过JPA进行引导,并且已EntityManagerFactory
通过@PersistenceUnit
注释注入了:
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
您可以Sessionfactory
使用以下unwrap
方法轻松访问基础:
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
JPA可以完成相同的操作EntityManager
。如果您EntityManager
通过@PersistenceContext
注释注入:
@PersistenceContext
private EntityManager entityManager;
您可以Session
使用以下unwrap
方法轻松访问基础:
Session session = entityManager.unwrap(Session.class);
因此,您应该通过JPA进行引导,使用EntityManagerFactory
和EntityManager
,并且仅当您想访问JPA中不可用的某些特定于Hibernate的方法(例如通过其自然标识符获取实体)时,才将它们解包到与其关联的Hibernate接口。
通过使用EntityManager,代码不再与休眠紧密结合。但是为此,在使用中我们应该使用:
javax.persistence.EntityManager
代替
org.hibernate.ejb.HibernateEntityManager
同样,对于EntityManagerFactory,请使用javax接口。这样,代码就可以松散耦合。如果有一个比休眠更好的JPA 2实现,则切换将很容易。在极端情况下,我们可以将强制类型转换为HibernateEntityManager。
EntityManager接口类似于休眠状态下的sessionFactory。EntityManager在javax.persistance包下,而session和sessionFactory在org.hibernate.Session / sessionFactory包下。
实体管理器是JPA特定的,而session / sessionFactory是休眠的。