本文主要比较一下二者操作实体类的方法的关系和区别。
本文适用 Hibernate:4.3.11.Final 和 spring-data-jpa:1.10.4.RELEASE 。
Session:
Configuration configuration=new Configuration().configuration(); ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory=configuration.buildSessionFactory(serviceRegistry); Session session=factory.openSession(); Transaction transaction=session.beginTransaction(); //to do sth. transaction.commit(); session.cose(); sessionFactory.close();EntityManager:
EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("persistenceUnitName"); EntityManager entityManager=entityManagerFactory.createEntityManager(); EntityTransaction entityTransaction=entityManager.createEntityTransaction(); entityTransaction.begin(); //to do sth. entityTransaction.commit(); entityManager.close(); entityManagerFactory.close();SessionFactory 对应 EntityManagerFactory;
Session 对应 EntityManager;
SessionFactory是线程安全的,Session不是线程安全的;
EntityManager 是线程安全的;
Hibernate需要一个配置文件:hibernate.xml,文件在classpath可以访问即可。
JPA需要一个persistence.xml,文件必须是META/persistence.xml
如果整合Spring的话,就让他们随风去吧。
session的方法:
flush() evict() load() save() saveOrUpdate() update() merge() persist() delete() refresh() get()EntityManager的方法:
persist() merge() remove() find() flush() refresh() detach() getReference()从上面看出,jpa操作实体类的方法少了很多。
为了看起来不太混乱,以下用S代替Session,E代替EntityManager.
二者对应。
执行查询时返回代理对象,这是懒加载。spring-data-jpa中对应getOne();
如果数据库中没有对应的记录,抛异常。
注:这里spring-data-jpa又任性了,getOne()不是对应get(),注意。还有更任性的,如果对象在缓存中的话,那么getOne就会返回实体对象,否则返回代理对象。
执行查询时返回实体对象,立即加载。spring-data-jpa中对应findOne();
如果数据库中没有对应的记录,则返回null。
二者对应。
EntityManager没有save方法。
区别:
调用前的实体对象,如果主键使用setter设置了值,E.persist()会抛异常。而S.save()不会抛异常,只是会忽略。
区别:delete()可以移出持久化对象和游离对象,而remove只能移出持久化对象,否则会抛异常。
E.merge()当实体对象O1为临时对象,会创建一个新对象O2,执行insert操作,并返回这个新对象,相当于S.saveOrUpdate()。此时O2为持久化对象,而O1仍然是游离对象。
E.merge()当实体对象O1位游离对象,即主键不为空: 首先查询缓存中是否有该主键对应的持久化对象,如果有,将缓存中的对象提取为O2,然后根据O1的值修改O2,并对O2执行update,返回O2.
如果缓存中不存在,那么就发送一条select去查询数据库中是否有持久化对象,如果存在,查询返回的持久化对象O2,根据O1修改O2的属性,并对O2执行update;否则,新建一个临时对象O2,复制O1的属性,并对O2执行insert,返回O2。以上E.merge()类似于S.saveOrUpdate(),下面看一下Hibernate中的一种情况:
@Test @org.springframework.transaction.annotation.Transactional public void testHibernate(){ Session session=sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); User u1=(User) session.get(User.class, 1); User u2=new User(); u2.setId(1); session.saveOrUpdate(u2); System.out.println(u1==u2); transaction.commit(); session.close(); }Hibernate不允许缓存中存在两个持久化对象对应同一个主键。
而JPA中不抛异常:
@Test @Transactional public void testJpa(){ User u1=entityManager.find(User.class, 1); User u2=new User(); u2.setId(1); u2.setUserName("Jack"); User u3=entityManager.merge(u2); System.out.println(Arrays.asList(u1)); System.out.println(Arrays.asList(u2)); System.out.println(u1==u2); System.out.println(u1==u3); }这是由于JPA不是在缓存中加载了第二个同一主键的实体对象,而是进行了实体对象的拷贝。
再看S.merge():
@Test @org.springframework.transaction.annotation.Transactional public void testHibernateMerge(){ Session session=sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); User u1=(User) session.get(User.class, 1); User u2=new User(); u2.setId(1); User u3=(User) session.merge(u2); System.out.println(u1==u2); System.out.println(u1==u3); transaction.commit(); session.close(); }这样是可以的,也就是说在这种情况下,S.merge()=E.merge()。
