JPA

一、JPA簡介

JPA全稱為Java Persistence API。JPA提供了一種簡單高效的方式來管理Java對象(POJO)到關系型數據庫的映射,此類Java對象成為JPA實體或簡稱實體。JPA和Hibernate之間的關系,可以簡單的理解為JPA是標準接口,Hibernate是實現。從功能上來說,JPA現在就是Hibernate功能的一個子集。Hibernate 從3.2開始,就開始兼容JPA。Hibernate3.2獲得了Sun TCK的 JPA(Java Persistence API) 兼容認證。
??那么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的規范。

總的來說,JPA是規范,Hibernate是框架,JPA是持久化規范,而Hibernate實現了JPA。

二、JPA的實體狀態

實體對象的狀態,在Hibernate有瞬時、持久、離線三種,而JPA里有new,managed,detached,removed,兩者的這些狀態都是一一對應的。

三、JPA配置

我們看看基于Hibernate提供的一個比較完整的JPA2.1的配置文件。
pom.xml:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>    

<dependencies>
    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-core</artifactId>
       <version>5.1.0.Final</version>
       <scope>compile</scope>
     </dependency>

     <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.1.0.Final</version>
        <scope>compile</scope>
     </dependency>
 
     <!--Hibernate整合C3P0實現連接池-->
     <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>5.1.0.Final</version>
        <scope>runtime</scope>
        <exclusions>
           <exclusion>
             <groupId>com.mchange</groupId>
             <artifactId>c3p0</artifactId>
           </exclusion>
         </exclusions>
      </dependency>
    
      <dependency>
         <groupId>com.mchange</groupId>
         <artifactId>c3p0</artifactId>
         <version>0.9.5.2</version>
         <scope>runtime</scope>
      </dependency>

      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-ehcache</artifactId>
          <version>5.1.0.Final</version>
          <scope>runtime</scope>
       </dependency>

        <dependency>
          <groupId>net.sf.ehcache</groupId>
          <artifactId>ehcache</artifactId>
          <version>2.10.1</version>
          <scope>compile</scope>
        </dependency>

</dependencies>

persistence.xml:

<!--JPA2.1規范要求每一個持久化單元必須有一個名字,不能為空。即persistence-unit name="main"的name不能為空-->
 <persistence-unit name="main"  transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
          <!-- 指定連接數據庫所用的驅動 -->
          <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"></property>
          <!-- 指定連接數據庫的url,hibernate連接的數據庫名 -->
          <property name="hibernate.connection.url" value="jdbc:postgresql://128.27.10:8081/test"></property>
          <property name="hibernate.onnection.characterEncoding" value="UTF-8"></property>
          <!-- 指定連接數據庫的用戶名 -->
          <property name="hibernate.connection.username" value="root"></property>
          <!-- 指定連接數據庫的密碼 -->
          <property name="hibernate.connection.password" value="123"></property>
          <!-- Connection Pool Provider -->
          <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"></property>
          <!-- 指定連接池里最大連接數 -->
          <property name="hibernate.c3p0.max_size" value="256"></property>
          <!-- 指定連接池里最小連接數 -->
          <property name="hibernate.c3p0.min_size" value="4"></property>
          <!-- 指定連接池里連接的超時時長 -->
          <property name="hibernate.c3p0.timeout" value="4096"></property>
          <!-- 指定連接池里最大緩存多少個Statement對象 -->
          <property name="hibernate.c3p0.max_statements" value="100"></property>
          <property name="hibernate.c3p0.idle_test_period" value="120"></property>
          <property name="hibernate.c3p0.acquire_increment" value="2"></property>
          <property name="hibernate.c3p0.validate" value="true"></property>
          <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"></property>
          <property name="hibernate.cache.use_second_level_cache" value="true"></property>
          <property name="hibernate.cache.use_query_cache" value="true"></property>

          <!-- 指定數據庫方言 -->
          <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL9Dialect"></property>
          <!-- 根據需要自動創建數據表 -->
          <!--<property name="hibernate.hbm2ddl.auto" value="update"></property>-->
          <!-- 顯示Hibernate持久化操作所生成的SQL -->
          <property name="hibernate.show_sql" value="true"></property>
          <!-- 將SQL腳本進行格式化后再輸出 -->
          <property name="hibernate.format_sql" value="true"></property>

          <property name="hibernate.current_session_context_class" value="managed"></property>

          <property name="javax.persistence.validation.mode" value="none"></property>
        </properties>

    </persistence-unit>

四、JPA的基本使用

public class JPABase(){
    //實體管理器
    protected ThreadLocal<EntityManager> entityManager;

    public JPABase(ThreadLocal<EntityManager> tlemImpl) {
        this.entityManager= tlemImpl;
    }

    //得到當下的entityManager
    public EntityManager currentEM() {
        return (EntityManager)this.entityManager.get();
    }

    //新建一個entityManager
    public EntityManager newEM() {
        return ((EntityManager)this.entityManager.get()).getEntityManagerFactory().createEntityManager();
    }

    //啟動事務
    public void begin() throws IllegalStateException {
        ((EntityManager)this.entityManager.get()).getTransaction().begin();
    }

    //更新實體。當實體正在被容器管理時,你可以調用實體的set 方法對數據進行修改,在容器決定flush 時,更新的數據才會同步到數據庫。
    public void flush() throws TransactionRequiredException, PersistenceException {
        ((EntityManager)this.entityManager.get()).flush();
    }

    //提交事務
    public void commit() throws IllegalStateException, RollbackException {
        ((EntityManager)this.entityManager.get()).getTransaction().commit();
    }

    //撤消(回滾)當前事務。即撤消事務啟動后的所有數據庫更新操作,從而不對數據庫產生影響
    public void rollback() throws IllegalStateException, PersistenceException {
        ((EntityManager)this.entityManager.get()).getTransaction().rollback();
    }

    //使當前事務只能被撤消
    public void fail() throws IllegalStateException {
        ((EntityManager)this.entityManager.get()).getTransaction().setRollbackOnly();
    }

    //關閉事務
    public void close() throws IllegalStateException {
        ((EntityManager)this.entityManager.get()).close();
        this.entityManager.remove();
    }
     
     //給對象加鎖
     public void lock(Object o, LockModeType lock) throws IllegalStateException {
        ((EntityManager)this.entityManager.get()).lock(o, lock);
    }

    //添加實體,相當于add。通常persist之后會調用flush方法將實例插入數據庫中
    public void persist(Object o){
         ((EntityManager)this.entityManager.get()).persist(o);
    }

     //addOrUpdate
     public User merge(Object o){
       return ((EntityManager)this.entityManager.get()).merge(o);
    }

    //刪除對象
    public void delete(Object o){
         ((EntityManager)this.entityManager.get()).remove(o);
    }

    //返回Query對象,以執行JPQL語句
    public Query query(String jpql) {
        return ((EntityManager)this.entityManager.get()).createQuery(jpql);
    }
 
    //返回Query對象,以執行SQL語句
    public Query createNativeQuery(String sql) {
        return ((EntityManager)this.entityManager.get()).createNativeQuery(sql);
    }
}

五、JPA的高級查詢

首先讓我們來了解一下以下類:

CriteriaQuery:查詢構造器(查詢語句拼裝器)。組合要查詢的內容和查詢的條件。
CriteriaBuiller:CriteriaQuery工廠。
Root:查詢根對象,定義查詢的From子句中能出現的類型。CriteriaQuery.select(root)就可以拼裝出select * from User 這一串。
Predicate:構造條件器。Predicate[] 可以支持多個過濾條件。

構造高級查詢上下文:

public class CriteriaQueryContext<T> {
    public Class<T> e;
    public CriteriaQuery<T> c;
    public CriteriaBuilder b;
    public Root<T> r;
    ...
}
 public <X> CriteriaQueryContext<X> criteria(Class<X> class) {
        CriteriaQueryContext ctx = new CriteriaQueryContext();
        ctx.e = class;
        ctx.b = ((EntityManager)this.entityManager.get()).getCriteriaBuilder();
        ctx.c = ctx.b.createQuery(class);
        ctx.r = ctx.c.from(class);
        return ctx;
    }

查詢條件的使用
??在criteria 查詢中,查詢條件通過Predicate 或Expression 實例應用到CriteriaQuery 對象上,這些條件使用 CriteriaQuery .where 方法應用到CriteriaQuery對象上
??CriteriaBuilder 也是作為Predicate 實例的工廠,Predicate對象通過調用CriteriaBuilder 的條件方法( equal,notEqual, gt, ge,lt, le,between,like等)創建。 Predicate實例也可以用Expression實例的isNull, isNotNull 和in方法獲得,復合的Predicate 語句可以使用CriteriaBuilder的and, or等方法構建。
下面的代碼片段展示了Predicate 實例檢查年齡大于24歲的員工實例:

 public User getUserById(String userId)
    {
        CriteriaQueryContext<User> c = this.criteria(User.class);
        Predicate condition =  c.b.equal(c.r.<String>get("userid"), userId);
        c.c.where(condition);
        return(
            this.entityManager.createQuery(c.c).getSingleResult();
        );
    }

Expression 用在查詢語句的select,where和having子句中,該接口有 isNull, isNotNull 和 in方法。

 CriteriaQueryContext<User> c = this.criteria(User.class);
 c.c.where(c.r.get(User.age).in(20, 24));

Criteria Query也允許開發者編寫復合謂詞,通過該查詢可以為多條件測試下面的查詢檢查兩個條件。

CriteriaQueryContext<User> c = this.criteria(User.class);
c.c.where(
 criteriaBuilder.and(
  criteriaBuilder.like(c.r.get(User.name), "M%"),
  criteriaBuilder.equal(c.r.get(User.age), 25)
));

我們也可以使用Predicate[]來添加多個過濾條件,Predicate[]使用模式為:

List<Predicate> predicatesList = new ArrayList<Predicate>();
predicatesList.add(.....Pridicate....)
criteriaQuery.where(predicatesList.toArray(new Predicate[predicatesList.size()]));

Predicate[]的demo:

List<Predicate> predicatesList = new ArrayList<Predicate>();
Predicate p1 = c.b.in(c.r.get("id")).value(id);
predicatesList.add(p1);
Predicate p2 = c.b.in(c.r.get("name")).value(name);
predicatesList.add(p2);
c.c.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
c.c.orderBy(c.b.asc(c.r.get(age)));
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,656評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,697評論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,098評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,855評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,254評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,473評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,014評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,833評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,016評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,273評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,680評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,946評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,730評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,006評論 2 374

推薦閱讀更多精彩內容