jpa的使用

本文章只是自己在学习中记的笔记(可能有点乱),只提供参考。如有错误请指出

什么是jpa

JPA (Java Persistence API)Java持久化API。是一套Sun公司Java官方制定的ORM方案,是规范,是标准 ,sun公司自己并没有实现

  • ORM是什么

    对象关系映射,ORM是一个实现使用对象操作数据库的设计思想,主要目的是操作实体类就相当于操作数据库。不再重点关注sql语句。

  • JPA的实现者

    JPA只是是一套标准。它只是一套实现ORM理论的接口。没有实现的代码。那么我们必须要有具体的实现者才可以完成ORM操作功能的实现!

    市场上的主流的JPA框架(实现者)有:

    • Hibernate (JBoos)
    • EclipseTop(Eclipse社区)
    • OpenJPA (Apache基金会)

Hibernate实现

hibernate是一个开放源码的对象关系映射框架

  1. 它对jdbc进行了非常轻量级的对象封装。

  2. 它将实体类与数据库表建立映射关系,是一个全自动的orm框架。

案例说明

对用户的增删改查操作

  • 项目搭建

    导入对应的maven坐标

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-entitymanager</artifactId>
                <version>5.4.10.Final</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-c3p0</artifactId>
                <version>5.4.10.Final</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.19</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/log4j/log4j -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
                <scope>provided</scope>
            </dependency>
    
  • 配置相关的jpa配置文件

    1. 配置文件在类路径下的一个叫META-INF的文件下。

    2. 它的文件命名也有要求。叫persistence.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
          <!--  持久化单元,name 持久化单元名称  transaction-type事务管理的方式
                  RESOURCE_LOCAL: 本地事务管理
                  JPA:分布式事务管理
          -->
          <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
              <!--  jpa的实现方式  -->
              <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
              <!-- <class>com.wlm.pojo.Customer</class>-->
              <!--  数据库信息  -->
              <properties>
                  <property name="javax.persistence.jdbc.user" value="root"/>
                  <property name="javax.persistence.jdbc.password" value="123"/>
                  <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
                  <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/website?serverTimezone=UTC&amp;useUnicod=true&amp;characterEncoding=utf-8"/>
      
                  <!--    可配置,配置jpa实现放的配置信息,也就是hibernate
                         显示sql
                         自动创建数据库表:
                              create:程序运行时创建数据库表(如果有表,先删除再创建)
                              ipdate:程序运行时再创建表(如果有表不会创建)
                              none:不会创建表
                 -->
                  <property name="hibernate.show_sql" value="true"/><!--  显示sql-->
                  <property name="hibernate.hbm2ddl.auto" value="update"/><!--自动创建数据库表-->
      <!--            <property name = "hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />&lt;!&ndash;方言&ndash;&gt;-->
              </properties>
          </persistence-unit>
      </persistence>
      
      • <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">配置持久化数据单元。

        1. name是 持久化单元名称,名称可以随便写,后面我们在程序中就是更具这名称获取对象。
        2. transaction-type事务管理的方式,它有2个选项:
        • RESOURCE_LOCAL: 本地事务管理。
        • JPA: 分布式事务管理。
      • <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>jpa的实现方式。因为jpa是接口,是规范,它没有对数据库的操作的实现。所以我们还要选择是那种方法实现jpa操作。这里是选用了hibernate方式。

      • <properties>里配置的是数据库信息。

        注意:其中数据库的信息字段,都要以javax.persistence.jdbc.开头。

   再后面2个属性,可配可不配,它是配置jpa实现放的配置信息,也就是hibernate。

   重点说下`hibernate.hbm2ddl.auto`,自动创建数据库表。它有3个可选对象。

   - create:程序运行时创建数据库表(如果有表,先删除再创建)
   - update:程序运行时再创建表(如果有表不会创建)
   - none:不会创建表。
  • 创建实体类

    @AllArgsConstructor
    @NoArgsConstructor
    @Setter
    @Getter
    @ToString
    //--------上面是lombok的注解--------
    @Entity
    @Table(name="User")
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;
        private String name;
        private String pwd;
        @Column(name = "create_time")
        private Date createTime;
    
    }
    

    注意:上面我用到了lombok。还有,所有的非lombok注解都是javax.persistence.*里的

    上面的注解是配置映射关系。映射关系的配置有两个方向:

    • 实体类和表的映射:
      1. @Entity:声明此类是一个实体类。
      2. @Table(name="User"):对应的是数据库中的表。name就是数据库中的表名
    • 实例类中属性和表中的字段映射:
      1. @Id:主键。
      2. @GeneratedValue(strategy = GenerationType.IDENTITY):定义的主键生成策略,其中有:
        • GenerationType.IDENTITY:自增。底层数据库必须支持自增才可以使用。像mysql。
        • GenerationType.SEQUENCE:序列。底层数据库必须支持序列才可以使用,像orac就支持,mysql不支持
        • GenerationType.TABLE:jpa提供的一种机制,它通过一张表的形式完成自增操作。(会在数据库中创建一张表),通过这张表来维护自增
        • GenerationType.AUTO:程序自动的选择主键策略。根据自己的表或运行环境选择上面三种策略。
      3. @Column(name = "id"):表中的字段映射,name,数据库中对应的字段名。
  • api操作

    • 增加操作

          @Test
          public void test() {
              //1.加载配置文件创建工厂(实体管理类工厂)对象,传入的是持久化数据单元,也就是配置文件里我们配置的数据单元。
              EntityManagerFactory jpa = Persistence.createEntityManagerFactory("myJpa");
      
              //2.通过工厂获取实体管理器
              EntityManager manager = jpa.createEntityManager();
      
              //获取事务对象
              EntityTransaction tx = manager.getTransaction();
              tx.begin();//开启事务
              //完成增删改查
              User User = new User();
              user.setName("nihao");
              user.setPwd("123");
              user.setCreateTime(new Date());
      
              //保存
              manager.persist(user);//保存操作
      
              //提交事务
              tx.commit();
      
              //关闭资源
              manager.close();
              jpa.close();
          }
      
  • 根据id查询用户

    引入一个概念,上面频繁通过工厂获取实体管理器,是一个比较耗资源和耗时的操作。所以我们可以把它放到一个静态代码块中,封装成一个工具类来获取,解决耗资源和耗时问题

    public class JpaUtils {
        private static EntityManagerFactory factory;
    
        static {
            factory = Persistence.createEntityManagerFactory("myJpa");
        }
    
        /*获取实体类管理器对象*/
        public static EntityManager getEntityManager(){
            return factory.createEntityManager();
        }
    
    }
    

    那么我们根据id查询代码实现:

     @Test
        public void test2() {
            //获取EntityManager对象
            EntityManager entityManager = JpaUtils.getEntityManager();
            //查询不需要事务,所以不用开启事务。
            //根据id查询操作
            /*
             * 要传入2个参数
             * class:查询数据的结果需要包装的实体类型的字节码
             * id:查询的主键的信息
             * */
    //        User user = entityManager.find(User.class, 1);//查询的第一种方法find();
            User user = entityManager.getReference(User.class, 1);//第二种方法。参数代表的类型都一样。
            /*
             * 这2种方法的区别有什么不一样?
             * find():查询的对象就是当前Userr本身。再调用的时候,sql发送的时机是立刻去数据库查询
             * getReference():查询的对象是一个代理类对象。sql发送的时机是什么时候调用,就什么时候发送。
             * 一般是使用getReference(),延迟加载方式。
             * */
            System.out.println(user);
            //释放EntityManager资源
            entityManager.close();
    
        }
    

    其中entityManager.findentityManager.getReference的作用和结果都是一样的。为啥要定义两个方法?

    • find():查询的对象就是当前User本身。再调用的时候,sql发送的时机是立刻去数据库查询
    • getReference():查询的对象是一个代理类对象。sql发送的时机是什么时候调用,就什么时候发送。(延迟加载)

    我们一般是使用getReference(),延迟加载方式来使用。

  • 删除客户的操作

      @Test
        public void testRemove() {
            EntityManager entityManager = JpaUtils.getEntityManager();
            //开启事务
            EntityTransaction tx = entityManager.getTransaction();
            tx.begin();//开启事务的操作
            //删除操作
            // 操作步骤
            /*
             * 1,先根据id查询到用户
             * 2,传入查询到的用户进行删除
             * */
            User User = entityManager.getReference(User.class, 2);
            entityManager.remove(User);
            tx.commit();
            entityManager.close();
        }
    
  • 更新操作

     @Test
        public void testUpdate() {
            EntityManager entityManager = JpaUtils.getEntityManager();
    
            EntityTransaction tx = entityManager.getTransaction();
            tx.begin();
    
            User User = entityManager.getReference(User.class, 2);
            User.setName("我我我我");
    
            //更新操作
            entityManager.merge(User);
            tx.commit();
            entityManager.close();
        }
    

    如果实体类中有写属性没值,那么更新操作后数据库那些字段也会没值。

  • 查询所有的操作

    @Test
        public void testFindAll() {
            EntityManager entityManager = JpaUtils.getEntityManager();
    
            //查询全部jqpl
            /*
             * jqpl:form User
             * sql:select * from User
             * */
            String jpql = "from User";
            Query query = entityManager.createQuery(jpql);
            //发送查询,并封装结果集
            List<User> list = query.getResultList();
            for (User o : list) {
                System.out.println(o);
            }
    
            entityManager.close();
        }
    

    这里引入了一个jpql

    sql:是查询表和表中的字段。

    jpql:是查询的实体类和类中的属性

    它们两的语法相识。

    比如:

    jqpl:form User
    sql:select * from User
    
  • 倒序查询全部用户,根据id倒序

      EntityManager entityManager = JpaUtils.getEntityManager();
    
            String jpql = "from User order by id desc";
            Query query = entityManager.createQuery(jpql);
    
            List<User> resultList = query.getResultList();
    
            for (User User : resultList) {
                System.out.println(User);
            }
            entityManager.close();
    
  • 使用jpql查询用户的总数

    @Test
    public void testCount() {
        EntityManager entityManager = JpaUtils.getEntityManager();
        String jpql = "select count(id) from User ";
        Query query = entityManager.createQuery(jpql);
        Object singleResult = query.getSingleResult();//获取一个结果的。
    
        System.out.println(singleResult);
        entityManager.close();
    }
    
  • 分页查询

    EntityManager entityManager = JpaUtils.getEntityManager();
            String jpql = "from User";
            //1.根据jpql创建query对象
            Query query = entityManager.createQuery(jpql);
            //2.对参数负赋值--分页参数
            query.setFirstResult(4);//起始索引,从0开始查,不包含0
            query.setMaxResults(2);//每页查询的条数
    
            List<User> resultList = query.getResultList();
    
            for (User User : resultList) {
                System.out.println(User);
            }
    
            entityManager.close();
    
  • 条件查询

     @Test
        public void testLike() {
            EntityManager entityManager = JpaUtils.getEntityManager();
            String jpql = "from User where name like ?1";
            //1.根据jpql创建query对象
            Query query = entityManager.createQuery(jpql);
            /*
             * 第一个参数是占位符的位置,默认是1开始
             * 第二个是 取值
             * */
            query.setParameter(1, "ni%");
            List<User> resultList = query.getResultList();
    
            for (User User : resultList) {
                System.out.println(User);
            }
    
            entityManager.close();
        }
    

    String jpql = "from User where name like ?1"中,占位符后是hpa的样式规定,有多个占位符,比如name like ?1 or pwd = ?2这样写,后面的数字是你设置占位符里的值的时候根据这数字去设置值。像query.setParameter(1, "ni%");

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容

  • 作者:钟昕灵,叩丁狼教育高级讲师。原创文章,转载请注明出处。 JPA简介 JPA是Java Persistence...
    叩丁狼教育阅读 4,154评论 1 5
  • 转自:jpa-内心求法 JPA概要摘要:JPA定义了Java ORM及实体操作API的标准。本文摘录了JPA的一些...
    谁在烽烟彼岸阅读 1,167评论 0 4
  • [TOC] ORM思想 ORM全称Object Relational Mapping,即对象关系映射,是一种程序设...
    风少侠阅读 7,512评论 0 0
  • 一 介绍 Java Persistence API:用于对象持久化的 APIJava EE 5.0 平台标准的OR...
    guideEmotion阅读 1,262评论 0 1
  • 金牛派阅读 130评论 0 0