零、本文纲要
一、基础准备
- 数据库准备
① 建表DDL - 创建Maven工程
① pom.xml
② persistence.xml
③ 创建实体类
二、基础CRUD
- 创建测试类
- CRUD测试
① 测试新增
② 测试查询
③ 测试更新
④ 测试删除
三、JPQL
- 查询全部
- 测试排序
- 测试计数(聚合)
- 测试分页查询
- 测试条件查询
一、基础准备
JPA是一种规范,Hibernate是具体的实现,帮助我们实现ORM操作。此处我们将进行基础的JPA操作,具体见下文。
1. 数据库准备
① 建表DDL
-- 客户信息表准备
create TABLE cst_customer (
`cust_id` BIGINT(32) not null AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` VARCHAR(32) not null COMMENT '客户名称(公司名称)',
`cust_source` VARCHAR(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` VARCHAR(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` VARCHAR(32) DEFAULT NULL COMMENT '客户级别',
`cust_address` VARCHAR(128) DEFAULT NULL COMMENT '客户联系地址',
`cust_phonoe` VARCHAR(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='客户信息表';
2. 创建Maven工程
① pom.xml
a、属性控制
UTF-8
5.0.7.Final
b、基础依赖
junit
junit
4.12
test
org.hibernate
hibernate-entitymanager
${project.hibernate.version}
org.hibernate
hibernate-c3p0
${project.hibernate.version}
log4j
log4j
1.2.17
mysql
mysql-connector-java
8.0.30
② persistence.xml
NOTE
JPA的配置文件 persistence.xml ,改文件有两点要求:
a、必须命名为persistence.xml;
b、必须放置于类加载路径下的META-INF包下。
NOTE
IDEA中创建 persistence.xml 配置文件的便捷方法:
File → Settings... → Editor → File and Code Templates → ...
具体如下 ⬇ ⬇ ⬇
配置文件具体如下:
org.hibernate.jpa.HibernatePersistenceProvider
③ 创建实体类
Customer 如下:
import javax.persistence.*;
/**
* 客户实体类
* → 配置映射关系
* 1. 实体类和表的映射关系;
* 2. 实体类中属性和表中字段的映射关系;
* → 实体类和表的映射关系
* ① @Entity:声明实体类;
* ② @Table:配置实体类和表的映射关系;
* → name:配置数据库表名称;
* → 实体类中属性和表中字段的映射关系
* ① @Id:声明主键的配置;
* ② @GeneratedValue:配置主键生成策略;
* → strategy:主键策略
* a、 GenerationType.IDENTITY 自增,MySQL数据库;
* 底层数据库必须支持自动增长,采用数据库自增方式对ID进行自增。
* b、 GenerationType.SEQUENCE 序列,Oracle数据库;
* 底层数据库支持序列。
* c、 GenerationType.TABLE
* JPA提供的一种机制,通过一张数据库表的形式帮助完成主键自增。
* d、 GenerationType.AUTO
* 由程序自动选择主键生成策略。
* ③ Column:实体类属性与表字段映射
* → name:数据库表字段名称
*/
@Table(name = "cst_customer")
@Entity
public class Customer {
/*客户主键*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId;
/*客户名称*/
@Column(name = "cust_name")
private String custName;
/*客户资源来源*/
@Column(name = "cust_source")
private String custSource;
/*客户级别*/
@Column(name = "cust_level")
private String custLevel;
/*客户所属行业*/
@Column(name = "cust_industry")
private String custIndustry;
/*客户的联系方式*/
@Column(name = "cust_phonoe")
private String custPhone;
/*客户地址*/
@Column(name = "cust_address")
private String custAddress;
/*
此处省略get|set方法、构造方法、toString方法等。
*/
}
二、基础CRUD
1. 创建测试类
/**
* 基础CRUD:
* 1. Create增 persist
* 2. Read查 find | getReference
* 3. Update改 merge
* 4. Delete删 remove
*/
public class JpaTest {
...
}
2. CRUD测试
① 测试新增
NOTE
JPA的操作的一般流程:
a、加载配置文件,使用Persistence创建工厂对象EntityManagerFactory (实体管理器工厂);
b、通过实体管理器工厂获取实体管理器EntityManager;
c、获取事务对象EntityTransaction;
d、开启事务;
e、进行增删改查操作;
f、提交事务|回滚事务;
g、释放资源。
/**
* 测试JPA保存
* 案例:保存一个客户到数据库中
* JPA操作步骤
* 1. 加载配置文件,创建工厂对象(实体管理器工厂);
* 2. 通过实体管理器工厂获取实体管理器;
* 3. 获取事务对象;
* 4. 开启事务;
* 5. 进行增删改查操作;
* 6. 提交事务|回滚事务;
* 7. 释放资源。
*/
@Test
public void testSave() {
// 1. 加载配置文件,创建工厂对象(实体管理器工厂)
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
// 2. 通过实体管理器工厂获取实体管理器
EntityManager entityManager = entityManagerFactory.createEntityManager();
// 3. 获取事务对象
EntityTransaction transaction = entityManager.getTransaction();
try {
// 4. 开启事务
transaction.begin();
// 5. 进行增删改查操作
Customer customer = new Customer();
customer.setCustName("Stone");
customer.setCustIndustry("Java");
// 实体管理器entityManager通过persist保存实体
entityManager.persist(customer);
// 6. 提交事务
transaction.commit();
} catch (Exception e) {
// 6. 回滚事务
transaction.rollback();
e.printStackTrace();
} finally {
// 7. 释放资源
// 释放实体管理器资源
try {
entityManager.clear();
entityManager.close();
} catch (Exception e) {
e.printStackTrace();
}
// 释放实体管理器工厂资源
try {
entityManagerFactory.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
NOTE
由于 EntityManagerFactory 每次创建非常占用资源,而且其本身即是线程安全的,实际使用中可以创建工具类。
具体如下 ⬇ ⬇ ⬇
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaEntityManagerUtil {
private static final EntityManagerFactory entityManagerFactory;
static {
// EntityManagerFactory的创建销毁占用资源,而且本身是线程安全的,所以仅加载一次即可
entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
}
public static EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
}
测试使用我们创建的工具类:
@Test
public void testUtil() {
// 1. 通过实体管理器工具类获取实体管理器
EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
// 2. 获取事务对象
EntityTransaction transaction = entityManager.getTransaction();
try {
// 3. 开启事务
transaction.begin();
// 4. 操作增删改查
Customer customer = new Customer();
customer.setCustName("Jeff");
customer.setCustIndustry("Java");
// 实体管理器entityManager通过persist保存实体
entityManager.persist(customer);
// 5. 提交事务
transaction.commit();
} catch (Exception e) {
// 5. 回滚事务
transaction.rollback();
e.printStackTrace();
} finally {
// 6. 释放资源
entityManager.close();
}
}
② 测试查询
NOTE
find方法:
a、及时查询;
b、查询出来的是Customer对象本身。getReference方法:
a、延时查询,当使用到查询结果时再进行查询;
b、查询出来的是Customer对象的代理对象。
/**
* find方法:
* 1. 及时查询;
* 2. 查询出来的是Customer对象本身;
*/
Customer customer = entityManager.find(Customer.class, 1L);
System.out.println(customer);
/**
* getReference方法:
* 1. 延时查询,当使用到查询结果时再进行查询;
* 2. 查询出来的是Customer对象的代理对象;
*/
Customer customer = entityManager.getReference(Customer.class, 1L);
System.out.println(customer);
③ 测试更新
NOTE
更新操作:先查询,后更新。使用指定主键查询,判断是否存在:
a、存在,进行更新操作;
b、不存在,会按照指定主键策略进行数据插入。注意:此处并不会按照指定查询的主键进行插入。
Customer customer = new Customer();
/*
设置主键用于查询:
① 存在,则更新数据;
② 不存在,则插入数据(注意:用于查询的主键不作为插入数据的一部分,而是跟据主键策略生成主键)。
*/
customer.setCustId(4L);
customer.setCustName("Stone");
customer.setCustIndustry("Java");
entityManager.merge(customer);
④ 测试删除
NOTE
删除操作:先查询,后更新。
// 先查询,后删除
// ① 跟据ID查询客户
Customer customer = entityManager.find(Customer.class, 3L);
// ② 删除指定客户
entityManager.remove(customer);
三、JPQL
JPQL:Java Persistence Query Language,Java持久化查询语言。
→ 与SQL对比:
1. SQL:查询表和表中的字段;
2. JPQL:查询实体类和类中的属性;
1. 查询全部
NOTE
与基础CRUD不同的地方,使用JPQL进行查询时,我们需要先获取 Query 对象,再使用其对应方法获取结果。
/**
* 测试查询全部
* → 与SQL对比:
* 1. SQL:SELECT * FROM cst_customer
* 2. JPQL:FROM com.stone.entity.Customer
*/
@Test
public void testFindAll() {
EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
// 1. 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer"
String JPQL = "FROM com.stone.entity.Customer";
// 2. 创建查询对象
Query query = entityManager.createQuery(JPQL);
// 3. 发送查询,获取结果
List customers = query.getResultList();
for (Object customer : customers) {
System.out.println(customer);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
e.printStackTrace();
} finally {
entityManager.close();
}
}
2. 测试排序
NOTE
在查询全部的语句后拼接 ORDER BY 规则即可。
/**
* 测试排序
* → 与SQL对比:
* 1. SQL:SELECT * FROM cst_customer ORDER BY cust_id DESC
* 2. JPQL:FROM com.stone.entity.Customer ORDER BY custId DESC
*/
@Test
public void testOrder() {
EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
// 1. 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer ORDER BY custId DESC"
String JPQL = "FROM com.stone.entity.Customer ORDER BY custId DESC";
// 2. 创建查询对象
Query query = entityManager.createQuery(JPQL);
// 3. 发送查询,获取结果
List customers = query.getResultList();
for (Object customer : customers) {
System.out.println(customer);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
e.printStackTrace();
} finally {
entityManager.close();
}
}
3. 测试计数(聚合)
NOTE
在查询全部的语句前拼接 SELECT COUNT(field_name) 聚合条件即可。
/**
* 测试计数(聚合)
* → 与SQL对比:
* 1. SQL:SELECT COUNT(cust_id) FROM cst_customer
* 2. JPQL:SELECT COUNT(custId) FROM com.stone.entity.Customer
* 注意:相比于上述的查询集合及排序,此处多了SELECT关键字。
*/
@Test
public void testCount() {
EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
// 1. 编写JPQL语句,此处也可以使用简写的方式 "SELECT COUNT(custId) FROM Customer"
String JPQL = "SELECT COUNT(custId) FROM com.stone.entity.Customer";
// 2. 创建查询对象
Query query = entityManager.createQuery(JPQL);
// 3. 发送查询,获取结果
Object result = query.getSingleResult();
System.out.println(result);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
e.printStackTrace();
} finally {
entityManager.close();
}
}
4. 测试分页查询
NOTE
相比于其他查询,该查询需要我们给 Query对象 设置相应的属性:
a、使用 setFirstResult 设置分页查询参数(起始索引从0开始);
b、使用 setMaxResults 设置每页容量。
/**
* 测试分页查询
* → 与SQL对比:
* 1. SQL:SELECT * FROM cst_customer LIMIT ?,?
* 2. JPQL:FROM com.stone.entity.Customer
*/
@Test
public void testPage() {
EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
// 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer"
String JPQL = "FROM com.stone.entity.Customer";
Query query = entityManager.createQuery(JPQL);
// query对象 → 设置分页查询参数
// ① 设置起始索引,起始索引从0开始
query.setFirstResult(0);
// ② 设置每页容量
query.setMaxResults(3);
List customers = query.getResultList();
for (Object customer : customers) {
System.out.println(customer);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
e.printStackTrace();
} finally {
entityManager.close();
}
}
5. 测试条件查询
NOTE
类似分页查询,该查询需要我们给 Query对象 设置相应的属性。setParameter(int position, Object value) 方法有两个参数:
a、第一个参数position:代表占位符所在位置,从1开始计数;
b、第二个参数value:代表具体替换的参数值。注意:分页索引从0开始计数,参数占位符从1开始计数。
/**
* 测试条件查询
* → 与SQL对比:
* 1. SQL:SELECT * FROM cst_customer WHERE cust_address LIKE ?
* 2. JPQL:FROM com.stone.entity.Customer WHERE custAddress LIKE ?
*/
@Test
public void testLike() {
EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
// 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer WHERE custAddress LIKE ?"
String JPQL = "FROM com.stone.entity.Customer WHERE custAddress LIKE ?";
Query query = entityManager.createQuery(JPQL);
/*
query对象 → 设置占位符参数值,setParameter(int position, Object value)
① 第一个参数position:代表占位符所在位置,从1开始计数;
② 第二个参数value:代表具体替换的参数值。
*/
query.setParameter(1, "%Longgang%");
query.setFirstResult(0);
query.setMaxResults(3);
List customers = query.getResultList();
for (Object customer : customers) {
System.out.println(customer);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
e.printStackTrace();
} finally {
entityManager.close();
}
}
四、结尾
以上即为Spring Data JPA-基础篇的全部内容,感谢阅读。