Spring Data开发手册|Java持久化API(JPA)需要了解到什么程度呢?

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
RDS Agent(兼容OpenClaw),2核4GB
简介: JPA,Java Persistence API是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。它的出现主要是为了简...

 image.gif

JPA,Java Persistence API是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合ORM技术

ORM:通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。本质就是将数据从一种形式转换到另外一种形式。

同时也结束了Hibernate、TopLink等ORM框架各自为营的局面。JPA充分吸收了Hibernate、TopLink等ORM框架的基础上发展起来的,使用方便,伸缩性强

注意: JPA不是一种新的ORM框架,它的出现只是用于规范现有的ORM技术,它不能取代现有的Hibernate等ORM框架,相反,采用JPA开发时,我们仍将使用这些ORM框架,只是此时开发出来的应用不在依赖于某个持久化提供商。应用可以在不修改代码的情况下载任何JPA环境下运行,真正做到低耦合,可扩展的程序设计。类似于JDBC,在JDBC出现以前,我们的程序针对特性的数据库API进行编程,但是现在我们只需要针对JDBC API编程,这样能够在不改变代码的情况下就能换成其他的数据库。

JPA是一套规范,不是一套产品。Hibernate是一套产品,如果这些产品实现了JPA规范,那么我们可以叫它们为JPA的实现产品。使用JPA,就可以把我们的应用从Hibernate中解脱出来,那么现在问题来了::如何使用JPA来开发呢?

准备好了吗,进入正题,起飞!

首先,先带大家看一下本篇文章的大致介绍。

没目录怎么知道这篇到底有多少干货呢?

    • 以前的开发模式
    • JPA是什么
    • JPA解决了什么问题
    • JPA的第一个HelloWord程序
    • 详解配置文件
    • 常用的注解
    • 一对一的问题
    • 一对多的问题
    • 多对多的问题
    • JPA中常见的方法
    • JPA中对象的状态
    • 注意事项

    是不是很清晰呢,什么?还不进入正文,来了,安排上,一个一个来:

    回顾以前的开发模式

    以前开发的时候我们的DAO层,要么使用Hibernate、要么使用iBatis、dbutils、toplink

    网络异常,图片无法展示
    |
    image.gif

    需求:假设现在的产品的1.0版本的DAO的实现使用的是Hibernate、现在老板要求将DAO层换成TopLink

    网络异常,图片无法展示
    |
    image.gif

    按照现在的解决方案整个DAO层都是需要重写的,很耗费人力和物力,增加了成本

    有没有一种方案?这种方案就是如果我们需要换ORM框架,我们的整个DAO层都不需要改变只是需要改变配置文件就可以了呢?

    JPA技术技术因此而生

    JPA是什么

    JPA实际上是sun公司出的一套规范、这套规范的作用是为了解决市场上ORM框架一家独大的问题

    image.gif

    JPA是一套规范,只要我们的ORM框架实现了这套规范,那么在使用这个ORM框架的时候,就不需要面对于某一种ORM产品的API来进行编程,而是统一的面向于JPA来进行编程,这个时候即使你的ORM产品改变了,那么你的DAO层面向于JPA编程的代码是不用变的

    网络异常,图片无法展示
    |
    image.gif

    JPA解决了什么问题

    JPA统一了ORM框架访问数据库的API

    JPA解决了ORM框架一家独大的问题

    JPA的第一个HelloWorld程序

    导包

    网络异常,图片无法展示
    |
    image.gif

    编写配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
     http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
     version="2.1">
     <persistence-unit name="hibernateJPA" transaction-type="RESOURCE_LOCAL">
      <properties>
       <property name="hibernate.hbm2ddl.auto" value="update"></property>
       <property name="hibernate.show_sql" value="true"></property>
       <property name="hibernate.format_sql" value="true"></property>
       <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"></property>
       <property name="hibernate.connection.url" value="jdbc:mysql:///qianyu"></property>
       <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
       <property name="hibernate.connection.username" value="root"></property>
       <property name="hibernate.connection.password" value="root"></property>
      </properties>
     </persistence-unit>
    </persistence>

    image.gif

    编写Java实体和注解

    @Table(name="t_user")     //设置当前的类的对象对应的表名字
    @Entity                   //表示当前的这个类是一个持久化的实体
    public class User {
     @Id                  //这个表示的是当前的字段是主键
     @GeneratedValue(strategy=GenerationType.IDENTITY)   //这个表示的是主键的生成策略(自增长)
     @Column(name="uId")
     private int uId;
     @Column(name="userName")   //列的名字
     private String userName;
     @Column(name="password")
     private String password;
    }

    image.gif

    测试

    @Test
     public void testHelloWorld() throws Exception {
      //第一步:创建实体管理的工厂
      EntityManagerFactory ef=Persistence.createEntityManagerFactory("hibernateJPA");
      //通过工厂创建实体的管理器
      EntityManager em=ef.createEntityManager();
      //第三步:开启事务
      em.getTransaction().begin();
      //操作业务逻辑
      User user=new User();
      user.setUserName("浅羽");
      user.setPassword("123");
      //保存用户实体到数据库
      em.persist(user);
      //提交事务
      em.getTransaction().commit();
      //关闭管理器
      em.close();
      ef.close();
     }

    image.gif

    详解配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
     http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
     version="2.1">
        <!--
             persistence-unit:这个叫做持久化的单元   这个的作用就是配置 访问数据库的信息
             name:逻辑意义上可以随便写  但是一般情况下见名之意  这个一般情况下写JPA的实现产品的名字
             transaction-type:事务的类型
                RESOURCE_LOCAL:局部事务
                        事务的分类   
                             全局事务
                                   举例:张三给李四转账(建设银行----中国银行)          
                             局部事务
                                   举例:所有的操作在同一个库里头执行          
                             粗粒度事务
                                  举例:能够对整个类或者方法体进行事务的管理           
                             细粒度事务    
                                  举例:就是能够对某几行代码进行事务的管理                                  
        -->
     <persistence-unit name="hibernateJPA" transaction-type="RESOURCE_LOCAL">
      <properties>
       <property name="hibernate.hbm2ddl.auto" value="update"></property>
       <property name="hibernate.show_sql" value="true"></property>
       <property name="hibernate.format_sql" value="true"></property>
       <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"></property>
       <property name="hibernate.connection.url" value="jdbc:mysql:///qianyu"></property>
       <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
       <property name="hibernate.connection.username" value="root"></property>
       <property name="hibernate.connection.password" value="root"></property>
      </properties>
     </persistence-unit>
    </persistence>

    image.gif

    常用的注解线程池技术

    @Table:表示的是当前的实体对应的数据库中的表名字
    @Entity:表示的是当前的实体是一个持久化的实体
    @Id:这个表示当前的属性是一个主键
    @GeneratedValue:主键的生成策略
    strategy=GenerationType.IDENTITY:这个表示的是主键自增长
    strategy=GenerationType.AUTO:使用表来生成目标表的主键
    strategy=GenerationType.SEQUENCE:使用序列来生成主键
    @Column:jAVA的属性对应的数据库表的列的名字
    Name:名字
    Length:表示的是字段的长度
    nullable=false:这个表示的是不能为null
    unique=true:是否是唯一的
    @Transient :当前字段在数据库中不对应列
    @Enumerated:表示的是枚举在数据库中的映射使用下标还是字符串
    EnumType.STRING:表示的是以字符串的形式显示
    EnumType.ORDINAL:表示枚举在数据中以下标的形式显示
    @Lob:修饰String类型的时候 表示的大文本
           修饰byte[]的时候表示存储的是二进制

    image.gif

    一对一的问题

    需求:一个人对应了一个身份证、一个身份证也唯一对应了一个人

      • 身份证----->人
      • 一对一的关系

      代码演示:

      声明IdCard类

      @Entity
      @Table
      public class IdCard {
       @Id
       private String cardNum;
       private Date startTime;
       private Date endTime;
       //一个身份证唯一的对应了一个人
       @OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
       @JoinColumn(name="pId")     //这个表示的是添加一个列 这个列映射下面对象中的这个Id
       private People people;
      }

      image.gif

      声明People类

      @Entity
      @Table
      public class People {
       @Id
       @GeneratedValue(strategy=GenerationType.IDENTITY)
       private int pId;
       private String pName;
       private String pTel;
       //一个人对应了一个身份证
       //在关联关系中 配置了mappedBy的哪一方没有权限维护另外一方
       //mappedBy的值就是当前的类在下面对象中声明的这个名字
       @OneToOne(mappedBy="people",cascade=CascadeType.ALL)
       private IdCard idCard;
      }

      image.gif

      测试

      @Test
       public void testHelloWorld() throws Exception {
        EntityManager entityManager=JPAUtils.getEntityManager();
        IdCard idCard=new IdCard();
        idCard.setCardNum("510...x");
        idCard.setStartTime(new Date());
        idCard.setEndTime(new Date());
        People people=new People();
        people.setpName("小羽");
        people.setpTel("1234566");
        idCard.setPeople(people);
        entityManager.persist(idCard);
        JPAUtils.close();
       }

      image.gif

      一对多的问题

      需求:部门和员工的对应

        • 部门----->员工
        • 一对多的关联关系

        代码演示:

        声明部门对象

        @Entity
        @Table
        public class Dept {
         @Id
         @GeneratedValue(strategy=GenerationType.IDENTITY)
         private int dId;
         private String dName;
         private String dDes;
         //一个部门有多个员工
         @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="dept")
         private Set<Employee> emps;
        }

        image.gif

        声明员工对象

        @Entity
        @Table
        public class Employee {
         @Id
         @GeneratedValue(strategy=GenerationType.IDENTITY)
         private int empId;
         private String empName;
         @ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
         @JoinColumn(name="dId")
         private Dept dept;
        }

        image.gif

        测试

        @Test
         public void testOne2Many() throws Exception {
          EntityManager entityManager=JPAUtils.getEntityManager();
          Employee emp=new Employee();
          emp.setEmpName("小娜");
          Dept dept=new Dept();
          dept.setdName("研发部");
          dept.setdDes("专门搞开发的");
          emp.setDept(dept);
          entityManager.persist(emp);
          JPAUtils.close();
         }

        image.gif

        多对多的问题

        需求:一个学生可以被多个老师教,一个老师也可以教多个学生

          • 学生----->老师            一对多
          • 老师----->学生            一对多
          • 老师和学生的最终关系    多对多的关联关系

          代码演示:

          编写老师实体

          @Entity
          @Table
          public class Teacher {
           @Id
           private String tNum;
           private String tName;
           @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
           @JoinTable(name="t_teacher_student",
           joinColumns=@JoinColumn(name="tNum"),          //映射的是当前这个类的主键
           inverseJoinColumns={@JoinColumn(name="stuNum")})     //映射的是对方表的主键
           private Set<Student> students;
          }

          image.gif

          编写学生实体

          @Entity 
          @Table
          public class Student {
           @Id
           private int stuNum;
           private String stuName;
           private int age;
           @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="students")
           private Set<Teacher> teachers;
          }

          image.gif

          测试

          @Test
           public void testMany2Many() throws Exception {
            EntityManager em=JPAUtils.getEntityManager();
            Teacher teacher=new Teacher();
            teacher.settName("小羽");
            teacher.settNum("007");
            Set<Student> students=new HashSet<Student>();
            Student student=new Student();
            student.setAge(18);
            student.setStuName("小白");
            student.setStuNum(100);
            Student student1=new Student();
            student1.setAge(19);
            student1.setStuName("小娜");
            student1.setStuNum(1000);
            Student student2=new Student();
            student2.setAge(20);
            student2.setStuName("小黑");
            student2.setStuNum(10000);
            students.add(student);
            students.add(student1);
            students.add(student2);
            teacher.setStudents(students);
            em.persist(teacher);
            JPAUtils.close();
           }

          image.gif

          JPA中常见的方法

          代码演示:

          常见方法

          public void testMethod() throws Exception {
            EntityManager entityManager=JPAUtils.getEntityManager();
            User user= new User();
            user.setUserName("小灰");
            user.setuId(1);
            //添加数据的方法
          //  entityManager.persist(user);
            //查询数据
            //User user2=entityManager.find(User.class,1);
            //这个写的是HQL语句
          //  Query query=entityManager.createQuery("from User");
          //  List list=query.getResultList();
            //下面这个方法有主键值 那么就修改  没有主键值 就插入
            //entityManager.merge(user);
            /*创建的是本地SQL的查询
            Query query=entityManager.createNativeQuery("select * from user");
            List list=query.getResultList();*/
            //一般用在查询中 获取最新的这个数据
          //  entityManager.refresh(user);
            User user2=entityManager.find(User.class,1);
            entityManager.remove(user2);
            //System.out.println(list);
            JPAUtils.close();
           }

          image.gif

          JPA中对象的状态

          对象的状态:

            • 新建状态: User user = new User();和数据库以及内存没有任何关联,对象仅仅是被new出来之后的这种状态
            • 托管状态: 对象调用了find persist refresh merge或者查询之后的这个对象状态就叫做托管状态,托管状态的数据是被entityManager管理的,并且内存和数据库的数据是对应了,这个时候如果你改变了内存的这个数据的话,并且进行提交的话,那么这个数据会和数据库进行同步
            • 游离状态: 当前的对象调用了clear方法之后在close方法之前的这段时间,这个对象处于游离状态。clear:表示的是清楚内存和数据库数据的对应的关系
            • 删除状态: 当前对象close之后的对象的这种状态,就称为删除状态

             

            注意事项

            表名不写默认就是类作为表名

            column不写,表的列名就是类的属性名

            @GeneratedValue后面值不写默认是auto

            结语

            JPA是我们开发中离不开的经常用到的技术,其涉及的技术和知识面其实远不止上面列出的这些。

            后续浅羽会继续更新关于JPA的开发知识,只希望能对大家有所帮助,谢谢大家的支持!

            image.gif

            点点点,一键三连都在这儿!

            相关实践学习
            每个IT人都想学的“Web应用上云经典架构”实战
            本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
            MySQL数据库入门学习
            本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
            相关文章
            |
            9月前
            |
            JSON Java API
            【干货满满】分享京东API接口到手价,用Java语言实现
            本示例使用 Java 调用京东开放平台商品价格及优惠信息 API,通过商品详情和促销接口获取到手价(含优惠券、满减等),包含签名生成、HTTP 请求及响应解析逻辑,适用于比价工具、电商系统集成等场景。
            |
            缓存 监控 负载均衡
            如何提升 API 性能:来自 Java 和测试开发者的优化建议
            本文探讨了如何优化API响应时间,提升用户体验。通过缓存(如Redis/Memcached)、减少数据负载(REST过滤字段或GraphQL精确请求)、负载均衡(Nginx/AWS等工具)、数据压缩(Gzip/Brotli)、限流节流、监控性能(Apipost/New Relic等工具)、升级基础设施、减少第三方依赖、优化数据库查询及采用异步处理等方式,可显著提高API速度。快速响应的API不仅让用户满意,还能增强应用整体性能。
            |
            监控 Java 应用服务中间件
            高级java面试---spring.factories文件的解析源码API机制
            【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
            514 2
            |
            9月前
            |
            JSON Java API
            【干货满满】分享拼多多API接口到手价,用Java语言实现
            本方案基于 Java 实现调用拼多多开放平台商品详情 API,通过联盟接口获取商品到手价(含拼团折扣与优惠券),包含签名生成、HTTP 请求及响应解析逻辑,适用于电商比价、导购系统集成。
            |
            9月前
            |
            JSON Java API
            【干货满满】分享淘宝API接口到手价,用Java语言实现
            本文介绍了如何使用 Java 调用淘宝开放平台 API 获取商品到手价,涵盖依赖配置、签名生成、HTTP 请求与响应解析等核心实现步骤。
            |
            10月前
            |
            JSON JavaScript 前端开发
            Python+JAVA+PHP语言,苏宁商品详情API
            调用苏宁商品详情API,可通过HTTP/HTTPS发送请求并解析响应数据,支持多种编程语言,如JavaScript、Java、PHP、C#、Ruby等。核心步骤包括构造请求URL、发送GET/POST请求及解析JSON/XML响应。不同语言示例展示了如何获取商品名称与价格等信息,实际使用时请参考苏宁开放平台最新文档以确保兼容性。
            |
            前端开发 Cloud Native Java
            Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
            博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
            Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
            |
            缓存 安全 Java
            《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
            🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
            366 11
            |
            存储 NoSQL Java
            使用Java和Spring Data构建数据访问层
            本文介绍了如何使用 Java 和 Spring Data 构建数据访问层的完整过程。通过创建实体类、存储库接口、服务类和控制器类,实现了对数据库的基本操作。这种方法不仅简化了数据访问层的开发,还提高了代码的可维护性和可读性。通过合理使用 Spring Data 提供的功能,可以大幅提升开发效率。
            412 21
            |
            数据采集 存储 Java
            Java爬虫获取微店店铺所有商品API接口设计与实现
            本文介绍如何使用Java设计并实现一个爬虫程序,以获取微店店铺的所有商品信息。通过HttpClient发送HTTP请求,Jsoup解析HTML页面,提取商品名称、价格、图片链接等数据,并将其存储到本地文件或数据库中。文中详细描述了爬虫的设计思路、代码实现及注意事项,包括反爬虫机制、数据合法性和性能优化。此方法可帮助商家了解竞争对手,为消费者提供更全面的商品比较。