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阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容