一篇 JPA 总结
概述
下面是 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)
- 创建 presitence.xml,在这个文件中配置持久化单元
导入 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 对应 identity,MySQL 对应 auto increment
- IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式
- AUTO: JPA自动选择合适的策略,是默认选项
- TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
- SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式
- @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment
@Basic
- 表示一个简单的属性到数据表的字段的映射,对于没有任何标注的 getXxx() 方法,默认为 @Basic
- fetch 表示属性的读取策略,有 EAGER 和 LAZY 两种,分别为主支抓取和延迟加载
- optional 表示该属性是否允许为 null,默认为 true
- 表示一个简单的属性到数据表的字段的映射,对于没有任何标注的 getXxx() 方法,默认为 @Basic
@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 语句)
- 保存数据(先保存不维护关联关系的一端,否则会多出 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(),用于执行update或delete语句。
- 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,其需要属性 DataSource、jpaVendorAdapter(JPA 提供商的适配器,通过内部 bean 的方式)、packagesToScan(Entity 在哪个包下),配置 JPA 基本属性(show_sql 等)
- 配置 JPA 使用的事务管理器(JPAtransactionManager)
- 配置事务
在 DAO 中使用 EntityManager
- 如何获取到和当前事务关联的 EntityManager 对象?
- 通过 @PesistenceContext 注解标记成员变量
一览图
以上就是我所学到有关 JPA 的知识,还望有用!再就是希望大牛们可以提点建设性的建议,共同进步,先谢谢了!
一篇 JPA 总结的更多相关文章
- Spring Boot 揭秘与实战(二) 数据存储篇 - JPA整合
文章目录 1. 环境依赖 2. 数据源 3. 脚本初始化 4. JPA 整合方案一 通过继承 JpaRepository 接口 4.1. 实体对象 4.2. DAO相关 4.3. Service相关 ...
- SpringBoot入门系列:第五篇 JPA mysql(转)
一,准备工作,建立spring-boot-sample-mysql工程1.http://start.spring.io/ A.Artifact中输入spring-boot-sample-mysql B ...
- 一篇 SpringData+JPA 总结
概述 SpringData,Spring 的一个子项目,用于简化数据库访问,支持 NoSQL 和关系数据库存储 SpringData 项目所支持 NoSQL 存储 MongDB(文档数据库) Neo4 ...
- Spring Data Jpa 复杂查询总结
实体类 @Entity @Table(name = "t_hotel") @Data public class THotel { @Id private int id; priva ...
- 转 springboot 教程
转 Spring Boot 揭秘与实战 系列 拓展阅读: https://zhuanlan.zhihu.com/dreawer?topic=Java 发表于 2016-12-21 | Spring框架 ...
- TGL站长关于常见问题的回复
问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...
- 从.Net到Java学习第十二篇——SpringBoot+JPA提供跨域接口
从.Net到Java学习系列目录 最近又撸了半个月的前端代码,做app离线存储,然后又花了一周去将过去的wcf项目转webapi,java又被落下了,总感觉我特么像斗地主中的癞子牌,变来变去..... ...
- 工具篇-Spring boot JPA多数据源
写这篇博文是因为这个东西坑太多,首先说明下边实现的多数据源不是动态切换的,应该算是静态的. 坑一.pom文件 pom中spring boot以及mysql connector的版本一定要注意. < ...
- SpringBoot系列教程JPA之query使用姿势详解之基础篇
前面的几篇文章分别介绍了CURD中的增删改,接下来进入最最常见的查询篇,看一下使用jpa进行db的记录查询时,可以怎么玩 本篇将介绍一些基础的查询使用姿势,主要包括根据字段查询,and/or/in/l ...
随机推荐
- Keras实现VGG16
一.代码实现 # -*- coding: utf-8 -*- """ Created on Sat Feb 9 15:33:39 2019 @author: zhen & ...
- HanLP汉语言分析框架
HanLP(Han Language Processing)是由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用. HanLP具备功能完善.性能高效.架构清晰.语料时新. ...
- Troubleshooting SQL Server RESOURCE_SEMAPHORE Waittype Memory Issues
前言: 本文是对博客https://www.mssqltips.com/sqlservertip/2827/troubleshooting-sql-server-resourcesemaphore-w ...
- c/c++ 模板与STL小例子系列<三> traits
c/c++ 模板与STL小例子系列 traits 对这个概念,还是处于懵逼的状态,初步体会就是,为了解决类型之间的转换问题. 从一个类型为A的指针,转化到类型为B的指针,中间需要用void*来作为中介 ...
- es6的正则扩展笔记之修饰符
es6对于正则表达式添加了 u 修饰符和 y 修饰符. u 修饰符:含义为“Unicode模式”,用来正确处理大于\uFFFF的Unicode字符. 该修饰符不光会正确处理正则表达式,还会正确处 ...
- zTree获取当前节点的下一级子节点数
使用zTree插件实现树形图中,需要获取当前点击的父节点的子节点数的需求,使用treeNode.children获取子节点数据集合,使用length方法获取集合长度.将当前节点的treeNode传入即 ...
- java操作elasticsearch实现组合桶聚合
1.terms分组查询 //分组聚合 @Test public void test40() throws UnknownHostException{ //1.指定es集群 cluster.name 是 ...
- MySQL 初识别语句,数据库、表、行的增删改查
一.MySQL 开场语句 1.登陆 mysql -u root -p ; #回车然后输入密码 2.退出 eixt | quit #二者选其一 3.查看数据文件路径(配置文件中学习的) show glo ...
- Linux 基本操作--文件查看 (day3)
一.查看文件-----cat (详情参考:http://blog.sina.com.cn/s/blog_52f6ead0010127xm.html) 语法结构: cat 查看方式 文件 cat -A ...
- A - Packets 贪心
A factory produces products packed in square packets of the same height h and of the sizes 1*1, 2*2, ...