概述

下面是 JDBC 在 Java 应用和数据库之间的位置,充当着一个中间者,供 Java 应用程序访问所有类别的数据库,建立一个标准

JPA 如同 JDBC 一样,为 Java 应用程序使用 ORM 框架建立一个标准

  • JPA 和 Hibernate 的关系
    • JPA 是规范:JPA 本质上是一种 ORM 规范,不是 ORM 框架,只是定制了一些规范,提供了一些编程的 API 接口,具体实现由 ORM 厂商实现
    • Hibernate 是实现:Hibernate 除了是一种 ORM 框架之外,他也是一种 JPA 实现

HelloWorld

  • 步骤

    • 创建 presitence.xml,在这个文件中配置持久化单元

      • 指定跟哪个数据库进行交互
      • 指定使用哪个持久化框架以及配置该框架的基本属性
    • 创建实体类,使用 annotation 来描述实体类跟数据库表之间的映射关系
    • 使用 JPA API 完成数据的增、删、改、查操作
      • 创建 EntityManagerFactory(对应于 Hibernate 中的 SessionFactory)
      • 创建 EntityManager(对应 Hibernate 中的 Session)
  • 导入 jar 包

      <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
    </dependency> <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>${hibernate.version}</version>
    </dependency> <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
    </dependency> <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.21</version>
    </dependency>
  • persistence.xml

    • JPA 规范要求在类路径的 META-INF 目录下防止 persistencce.xml,文件的名称是固定的

        <?xml version="1.0" encoding="UTF-8"?>
      <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
      <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
      <!--配置使用什么 ORM 产品-->
      <!--若 JPA 项目中只有一个 JPA 产品的实现,则可以不配置该节点-->
      <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.jpa.first.both.many2many.Item</class>
      <properties>
      <!--配置数据库连接-->
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa"/>
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
      <property name="hibernate.connection.username" value="root"/>
      <property name="hibernate.connection.password" value="zy961029"/> <!--配置 hibernate 的基本属性-->
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      </properties>
      </persistence-unit>
      </persistence>

注解

  • @Entity

    • @Entity 标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表。
  • @Table

    • 当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用
  • @id

    • @Id 标注用于声明一个实体类的属性映射为数据库的主键列
    • @Id标注也可置于属性的getter方法之前
  • @GeneratedValue

    • @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identityMySQL 对应 auto increment

      • IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式
      • AUTO: JPA自动选择合适的策略,是默认选项
      • TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
      • SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式
  • @Basic

    • 表示一个简单的属性到数据表的字段的映射,对于没有任何标注的 getXxx() 方法,默认为 @Basic

      • fetch 表示属性的读取策略,有 EAGER 和 LAZY 两种,分别为主支抓取和延迟加载
      • optional 表示该属性是否允许为 null,默认为 true
  • @Column

    • 当实体的属性与其映射的数据库表的列不同名时需要使用 @Column 标注说明,还有属性 unique、nullable、length
  • @Transient

    • 表示该属性并非一个到数据库表的字段的映射,ORM 框架将忽略该属性
    • 如果一个属性并非数据库表的字段映射,就务必将其标识为 @Transient,否则ORM 框架默认为其注解 @Basic,例如工具方法不需要映射
  • @Temporal

    • 在 JavaAPI 中没有定义 Date 类型的精度,而在数据库中表示 Date 类型的数据类型有 Date,Time,TimeStamp 三种精度(日期,时间,两者兼具),进行属性映射的时候可以使用 @Temporal 注解调整精度

JPA API

  • EntityManagerFactory

    • EntityManagerFactory 用来创建 EntityManager 实例
    • 使用 Persistence 类获取 EntityManagerFactory 实例,该类包含一个名为 createEntityManagerFactory 的静态方法
    • createEntityManager 有两个重载方法,如下:
    • 第二个重载方法和上述的方法唯一不同的是不需要传入第二个参数
    • isOpen(),检查 EntityManagerFactory 是否处于打开状态
    • close(),关闭 EntityManagerFactory,EntityManagerFactory 关闭后将释放所有资源,isOpen() 方法将返回 false
  • EntityManager

    • 代码

        public void testJpa() {
      // 创建 EntityManagerFactory
      String persistenceUnitName = "persistenceUnit";
      EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
      // 创建 EntityManager
      EntityManager entityManager = entityManagerFactory.createEntityManager();
      // 获取事务对象并开启事务
      EntityTransaction entityTransaction = entityManager.getTransaction();
      entityTransaction.begin();
      // 进行持久化操作
      entityManager.xxx();
      // 提交事务
      entityTransaction.commit();
      // 关闭 EntityManager
      entityManager.close();
      // 关闭 EntityManagerFactory
      entityManagerFactory.close();
      }
    • 常用方法测试

      • 我们在上述代码持久化部分测试以下方法,将初始化部分代码放入 @Before 内,将提交事务部分代码放入 @After 内,持久化操作方法在 @Test 内执行

          public class EntityManagerMethodTest {
        
              private EntityManagerFactory entityManagerFactory;
        private EntityManager entityManager;
        private EntityTransaction entityTransaction; @Before
        public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory("persistenceUnit");
        entityManager = entityManagerFactory.createEntityManager();
        entityTransaction = entityManager.getTransaction();
        entityTransaction.begin();
        } @After
        public void destroy() {
        entityTransaction.commit();
        entityManager.close();
        entityManagerFactory.close();
        } @Test
        public void test() {
        // 持久化操作
        }
        }
      • find():类似于 Hibernate 中 Session 的 get 方法

      • getReference():类似于 Hibernate 中 Session 的 load 方法,即在需要的时候才会去执行 SQL 语句,初始化对象,否则返回的为代理对象

      • persistence():类似于 Hibernate 中 Session 的 save 方法,但此方法所要存取的对象若有 id,那么会抛异常

      • remove():类似于 Hibernate 中 Session 的 delete 方法,但此方法只可删除持久化对象,而 hibernate 的方法可以删除游离对象(不在缓存中,但在数据库中可能有对象,该对象有 id;缓存是指利用方法从数据库中获取到对象且将其初始化了,那么关闭 entityManager、提交事务后该对象依旧可使用)

关联关系映射(使用 IDEA 可以使用实体生成表,也可以使用对应的额表逆向生成实体类)

  • 单向多对一(orders - customer)

    • 表结构(oreders 表中有 customer 表的外键映射 cus_id)

    • 实体映射

      •   @ToString
        @Entity
        @Table(name = "customer", schema = "jpa")
        public class CustomerEntity {
        private int id;
        private String cusName; @Id
        @Column(name = "id", nullable = false)
        @GeneratedValue(strategy = GenerationType.AUTO)
        public int getId() {
        return id;
        }
        public void setId(int id) {
        this.id = id;
        }
        @Basic
        @Column(name = "cus_name", nullable = true, length = 20)
        public String getCusName() {
        return cusName;
        }
        public void setCusName(String cusName) {
        this.cusName = cusName;
        }
        }
    • IDEA 逆向生成实体记得添加主键生成策略

    • 多对一映射方法测试

      • 添加数据

          /**
        * n-1 将数据插入表中,建议先插入一的一端
        */
        @Test
        public void testMany2OnePersistence() {
        CustomerEntity customerEntity = new CustomerEntity();
        customerEntity.setCusName("bgZyy"); OrdersEntity orderEntity1 = new OrdersEntity(); orderEntity1.setOrderNaem("CC-a-AA"); OrdersEntity orderEntity2 = new OrdersEntity();
        orderEntity2.setOrderNaem("DD-b-BB"); orderEntity1.setCustomerByCusId(customerEntity);
        orderEntity2.setCustomerByCusId(customerEntity); entityManager.persist(customerEntity);
        entityManager.persist(orderEntity1);
        entityManager.persist(orderEntity2);
        }
      • 获取数据

  • 单向一对多(company - employee)

    • 表结构

    • 实体映射

    • 关联关系维护

    • 一对多方法测试

      • 添加数据

          @Test
        public void testOne2ManyPersistence() {
        CompanyEntity companyEntity = new CompanyEntity();
        companyEntity.setComName("IT"); EmployeeEntity employeesEntity = new EmployeeEntity();
        employeesEntity.setEmpName("gg"); EmployeeEntity employeesEntity1 = new EmployeeEntity();
        employeesEntity1.setEmpName("yy");
        // 员工集合
        Collection<EmployeeEntity> employeeEntities = new ArrayList<>();
        employeeEntities.add(employeesEntity);
        employeeEntities.add(employeesEntity1);
        // 为 company 添加员工的集合信息
        companyEntity.setEmployeesById(employeeEntities);
        // 执行保存操作
        entityManager.persist(employeesEntity);
        entityManager.persist(employeesEntity1);
        entityManager.persist(companyEntity);
        }
      • 获取数据

          @Test
        public void testOne2ManyFind() {
        CompanyEntity companyEntity;
        companyEntity = entityManager.find(CompanyEntity.class, 1); System.out.println(companyEntity.getComName()); System.out.println(companyEntity.getEmployeesById().size());
        }
  • 双向一对一映射

    • 表结构

    • 实体映射

    • 方法测试

      • 保存数据(先保存不维护关联关系的一端,否则会多出 UPDATE 语句)

    • 使用 IDEA 反向生成实体(双向一对一

  • 双向多对多映射

    • 配置一览图(实体生成数据表),核心配置如下图所示,对于添加数据获取数据代码不再展示

JPQL(Java Persistence Query Language)

  • JPQL 语言可以是 select、update、delete 语句,他们都是通过 Query 接口封装执行的。
  • Query接口封装了执行数据库查询的相关方法。调用 EntityManager 的 createQuery、create NamedQuery 及 createNativeQuery 方法可以获得查询对象,进而可调用 Query 接口的相关方法来执行查询操作。
  • 方法测试
    • 获取某一范围所有属性的集合

    • 获取某一范围部分属性的集合,其和获取所有属性的集合所使用的方法一样,不同的是 jpql 语句不一样,且需要对应的实体有部分属性的构造器

    • 使用本地 SQL 语句查询,和以上两个所使用的方法不一样,此时使用 createNativeQuery()

JPQL 还支持二级缓存,order by 子句,group by 子句,聚合查询,having 子句,关联查询,子查询等,JPQL 还有大量函数,如字符串处理函数,算术函数和日期函数等功能,这里就不再一一列举,下面列出常用的方法和函数(了解即可):

  • 常用函数

    • concat(String s1, String s2):字符串合并/连接函数。
    • substring(String s, int start, int length):取字串函数。
    • trim([leading|trailing|both,] [char c,] String s):从字符串中去掉首/尾指定的字符或空格。
    • lower(String s):将字符串转换成小写形式。
    • upper(String s):将字符串转换成大写形式。
    • length(String s):求字符串的长度。
  • Query 接口主要方法

    • int executeUpdate(),用于执行updatedelete语句。
    • List getResultList(),用于执行select语句并返回结果集实体列表。
    • Object getSingleResult(),用于执行只返回单个结果实体的select语句
    • Query setFirstResult(int startPosition),用于设置从哪个实体记录开始返回查询结果。
    • Query setMaxResults(int maxResult),用于设置返回结果实体的最大数。与setFirstResult结合使用可实现分页查询。

Spring 整合 JPA

  • 整合什么

    • Spring 管理 EntityManager,JPA 使用声明式事务
  • 使用什么整合

    • LocalContainerEntityManagerFactoryBean,其适用于所有环境
  • 整合步骤

    • jar 包

      • Spring + Hibernate + JPA + C3P0 + MySQL
    • 创建 Spring 配置文件

      • 配置数据源
      • 配置 EntityManagerFactoryBean,即 LocalContainerEntityManagerFactoryBean,其需要属性 DataSourcejpaVendorAdapter(JPA 提供商的适配器,通过内部 bean 的方式)、packagesToScan(Entity 在哪个包下),配置 JPA 基本属性(show_sql 等)
      • 配置 JPA 使用的事务管理器(JPAtransactionManager)
      • 配置事务
    • 在 DAO 中使用 EntityManager

      • 如何获取到和当前事务关联的 EntityManager 对象?
      • 通过 @PesistenceContext 注解标记成员变量
    • 一览图

以上就是我所学到有关 JPA 的知识,还望有用!再就是希望大牛们可以提点建设性的建议,共同进步,先谢谢了!

一篇 JPA 总结的更多相关文章

  1. Spring Boot 揭秘与实战(二) 数据存储篇 - JPA整合

    文章目录 1. 环境依赖 2. 数据源 3. 脚本初始化 4. JPA 整合方案一 通过继承 JpaRepository 接口 4.1. 实体对象 4.2. DAO相关 4.3. Service相关 ...

  2. SpringBoot入门系列:第五篇 JPA mysql(转)

    一,准备工作,建立spring-boot-sample-mysql工程1.http://start.spring.io/ A.Artifact中输入spring-boot-sample-mysql B ...

  3. 一篇 SpringData+JPA 总结

    概述 SpringData,Spring 的一个子项目,用于简化数据库访问,支持 NoSQL 和关系数据库存储 SpringData 项目所支持 NoSQL 存储 MongDB(文档数据库) Neo4 ...

  4. Spring Data Jpa 复杂查询总结

    实体类 @Entity @Table(name = "t_hotel") @Data public class THotel { @Id private int id; priva ...

  5. 转 springboot 教程

    转 Spring Boot 揭秘与实战 系列 拓展阅读: https://zhuanlan.zhihu.com/dreawer?topic=Java 发表于 2016-12-21 | Spring框架 ...

  6. TGL站长关于常见问题的回复

    问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...

  7. 从.Net到Java学习第十二篇——SpringBoot+JPA提供跨域接口

    从.Net到Java学习系列目录 最近又撸了半个月的前端代码,做app离线存储,然后又花了一周去将过去的wcf项目转webapi,java又被落下了,总感觉我特么像斗地主中的癞子牌,变来变去..... ...

  8. 工具篇-Spring boot JPA多数据源

    写这篇博文是因为这个东西坑太多,首先说明下边实现的多数据源不是动态切换的,应该算是静态的. 坑一.pom文件 pom中spring boot以及mysql connector的版本一定要注意. < ...

  9. SpringBoot系列教程JPA之query使用姿势详解之基础篇

    前面的几篇文章分别介绍了CURD中的增删改,接下来进入最最常见的查询篇,看一下使用jpa进行db的记录查询时,可以怎么玩 本篇将介绍一些基础的查询使用姿势,主要包括根据字段查询,and/or/in/l ...

随机推荐

  1. 新闻思考-阿里进军游戏产业,苹果发力ARM芯片

    2018.04.03 大家好,这是我开通博客的第一篇文章,我希望在这里分享我的知识,也学习更多的知识,希望大家学习愉快. 阿里进军游戏产业,拿下旅行青蛙的代理权.腾讯一直在进攻阿里的核心业务:电商和支 ...

  2. mssql sqlserver 取消数值四舍五入的方法分享

    摘要: 下文讲述使用round sql函数,对数值型数据进行舍入操作 实验环境:sqlserver 2008 转自: http://www.maomao365.com/?p=6454 最近接到用户需求 ...

  3. C# 函数1 (函数的定义)

    1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 na ...

  4. 【公众号系列】SAP S/4 HANA 1809请查收

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[公众号系列]SAP S/4 HANA 1809 ...

  5. php学习----什么是常量

    PHP-什么是常量 1.什么是常量?常量可以理解为值不变的量(如圆周率):或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.PHP中的常量分为自定义常量和系统常量(后续小节会详细介绍). 2. ...

  6. 《Java大学教程》—第5章 数组

    5.6 增强的for循环:访问整个数组,读取数组元素,不基于数据下列5.7 数组方法:最大值.求和.成员访问.查找 1.答:P92存储固定个数相同数据类型的一组元素. 2.答:P92所有存储在一个特定 ...

  7. TCP Health Checks

    This chapter describes how to configure health checks for TCP. Introduction NGINX and NGINX Plus can ...

  8. TIPS FOR IMPROVING PERFORMANCE OF KAFKA PRODUCER

    When we are talking about performance of Kafka Producer, we are really talking about two different t ...

  9. E - Intervals 贪心

    Chiaki has n intervals and the i-th of them is [li, ri]. She wants to delete some intervals so that ...

  10. UVA1607-Gates(思维+二分)

    Problem UVA1607-Gates Accept: 111  Submit: 767Time Limit: 3000 mSec Problem Description Input The fi ...