JPA Java Persistence API,是Java EE 5的標准ORM接口,也是ejb3規范的一部分。
Hibernate,當今很流行的ORM框架,是JPA的一個實現,但是其功能是JPA的超集。
JPA和Hibernate之間的關系,可以簡單的理解為JPA是標准接口,Hibernate是實現。那么Hibernate是如何實現與JPA的這種關系的呢。
Hibernate主要是通過三個組件來實現的,及hibernate-annotation、hibernate-entitymanager和hibernate-core。
hibernate-annotation是Hibernate支持annotation方式配置的基礎,它包括了標准的JPA annotation以及Hibernate自身特殊功能的annotation。
hibernate-core是Hibernate的核心實現,提供了Hibernate所有的核心功能。
hibernate-entitymanager實現了標准的JPA,可以把它看成hibernate-core和JPA之間的適配器,它並不直接提供ORM的功能,而是對hibernate-core進行封裝,使得Hibernate符合JPA的規范。
Maven依賴:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.2.4.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.2.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.5.6-Final</version> </dependency>
下面重點介紹一下hibernate-entitymanager包的主要類及實現。
HibernatePersistence.java,實現了JPA的PersistenceProvider接口,它提供createEntityManagerFactory和createContainerEntityManagerFactory兩個方法來創建EntityManagerFactory對象,這兩個方法底層都是調用的EJB3Configuration對象的buildEntityManagerFactory方法,來解析JPA配置文件persistence.xml,,並創建EntityManagerFactory對象。
EntityManagerFactory對象的實現是EntityManagerFactoryImpl類,這個類有一個最重要的private屬性就是Hibernate的核心對象之一SessionFactory。這個類最重要的方法是createEntityManager,來返回EntityMnagaer對象,而sessionFactory屬性也傳入了該方法。
EntityManager對象的實現是EntityManagerImpl類,這個類繼承自AbstractEntityManagerImpl類,在AbstractEntityManager類中有一個抽象方法getSession來獲得Hibernate的Session對象,正是在這個Session對象的實際支持下,EntityManagerImpl類實現了JPA的EntityManager接口的所有方法,並完成實際的ORM操作。
此外,hibernate-entitymanager包中還有QueryImpl類利用EntityManagerImpl的支持實現了JPA的Query接口;TransactionImpl利用EntityManagerImpl的支持實現了JPA的EntityTransaction接口。
至此,Hibernate通過hibernate-entitymanager包完成了對於JPA的全部支持工作。
最后,補充一個讓我感到意外的問題:
JPA中的Query對象的getSingleResult()方法,當查詢不到結果時,拋出NoResultException、當查詢到多個結果時,拋出NonUniqueResultException;並且NoResultException和NonUniqueResultException都是RuntimeException。
這樣有兩個問題:
1、我認為getSingleResult方法應該允許查詢不到結果的情況存在的,此時它返回null即可,沒有必要拋出異常;
2、即使需要在查詢不到結果或者查詢到多個結果時拋出異常,也不應該拋出RuntimeException,因為這樣表示不需要代碼顯示的用try-catch塊來捕獲這些異常,也就不會引起用戶對這兩個異常的重視。
目前解決這個問題我使用的方法是
try{
Object o = query.getSingleResult(); } catch (NoResultException ex){ return null; }catch(NonUniqueResultException ex) { o = queryObject.getResultList(); return ((List)o).get(0); }