目录
1. 理解 JPA(Java Persistence API)
1.3 JPA 的基本注解:@Entity, @Table, @Id, @GeneratedValue
2.2 spring-boot-starter-data-jpa 的作用
2.3 配置 spring-boot-starter-data-jpa 依赖
3.2.1 引入基本的 Spring Data JPA 依赖
3.2.2 引入数据库连接池(默认使用 HikariCP)推荐默认的就行
3.2.4 配置 application.properties 或 application.yml
4.2 使用 JPA 的基本类型映射(如:@Column, @OneToMany, @ManyToOne 等)
JPA 提供了许多注解来描述实体类与数据库表之间的关系,包括对列、主键、关系的映射。
5.1 JpaRepository 和 CrudRepository 接口
5.1.2 JpaRepository 接口(推荐,实现的多)
5.5.3 使用 @Modifying 和 @Transactional 进行更新/删除操作
6.3 使用 Spring Data JPA 提供的分页与排序功能
8.2 使用 application.properties 配置数据库连接池
8.3 配置 JPA 的 Hibernate 属性(如:DDL 自动生成策略、SQL 日志输出等)
8.3.1 配置 Hibernate 的 DDL 自动生成策略
-
1. 理解 JPA(Java Persistence API)
-
1.1 什么是 JPA?
-
JPA(Java Persistence API)是 Java 平台的一部分,专门用于简化 Java 应用程序与关系型数据库之间的交互。它定义了一种标准的方式来映射 Java 对象到数据库表,同时提供了操作数据库(增、删、改、查)的接口,支持对象关系映射(ORM)。JPA 作为一种规范,定义了如何在 Java 应用程序中实现持久化,但并没有提供具体的实现。
JPA 的实现可以有多个,其中最常见的实现是 Hibernate,但也有其他实现,如 EclipseLink、OpenJPA 等。
-
-
1.2 JPA 与 Hibernate 的关系
-
Hibernate 是一个非常流行的 JPA 实现。它是一个开源的 ORM 框架,遵循了 JPA 的规范,并提供了一些额外的功能,比如自动生成 SQL、缓存机制等。简单来说,Hibernate 实现了 JPA 规范,它可以作为 JPA 的一个持久化提供者。
-
JPA 是一个规范,它规定了 Java 对象和关系型数据库之间的映射规则以及操作数据库的 API。
-
Hibernate 是一个实现,它提供了具体的代码来执行 JPA 规范中定义的操作。
-
例如,你可以使用 Hibernate 来实现 JPA 标准的接口,或者直接使用 Hibernate 提供的扩展功能。JPA 的目标是解耦持久化层,使得应用程序不依赖于某一个具体的实现,而是遵循 JPA 规范,便于切换实现。
-
-
1.3 JPA 的基本注解:
@Entity
,@Table
,@Id
,@GeneratedValue
-
在 JPA 中,注解是实现对象关系映射的关键。常见的注解包括:
-
@Entity:标识一个类是一个实体类,表示该类的实例将会与数据库中的一条记录映射。每个
@Entity
注解的类对应数据库中的一张表。-
@Entity
public class User {
// 类体
}
-
-
@Table:指定数据库表的名称。如果不使用该注解,默认情况下,实体类的名字将会被用作表名。通过
@Table
可以自定义表名以及其他表级别的配置(如 schema、catalog 等)。-
@Entity
@Table(name = "users")
public class User {
// 类体
}
-
-
@Id:指定实体类的主键字段。每个实体类必须至少有一个主键字段,JPA 使用该字段来唯一标识实体类的对象。
-
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 其他字段
}
-
-
@GeneratedValue:指定主键的生成策略。通常与
@Id
一起使用,表示主键的值如何自动生成。可以选择不同的生成策略,如AUTO
、IDENTITY
、SEQUENCE
等。GenerationType.AUTO
:JPA 容器根据数据库的不同选择合适的生成策略。GenerationType.IDENTITY
:通过数据库的自增列生成主键值。GenerationType.SEQUENCE
:使用数据库序列生成主键值(通常用于数据库支持序列的情况)。GenerationType.TABLE
:使用一个特殊的数据库表来生成主键(这种方式比较少见)。-
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 其他字段
}
-
-
1.4 JPA 与数据库表的映射
-
JPA 将 Java 对象(类)和数据库表之间进行映射,这种映射关系主要由注解和配置来定义。JPA 实现了对象关系映射(ORM),它能够将数据库中的记录转换为 Java 对象,并允许开发人员通过操作对象来间接操作数据库。
-
常见的映射关系如下:
-
一对一关系(@OneToOne):一个实体对应另一个实体的一个实例。
-
一对多关系(@OneToMany):一个实体对应多个实体。
-
多对一关系(@ManyToOne):多个实体对应一个实体。
-
多对多关系(@ManyToMany):多个实体对应多个实体。
-
-
举个例子,假设我们有一个
User
实体类和一个Address
实体类,一个用户可能有多个地址(多对一关系),那么我们可以使用@OneToMany
和@ManyToOne
来进行映射: -
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "user")
private List<Address> addresses;
// 其他字段和方法
}
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
-
-
-
2. Spring Data JPA 概述
-
2.1 什么是 Spring Data JPA?
-
Spring Data JPA 是 Spring Data 项目的一个子项目,它简化了基于 JPA(Java Persistence API)进行数据库操作的开发。Spring Data JPA 基于 JPA 规范,结合 Spring 的优势,提供了对 JPA 持久化技术的简化支持,特别是在 Spring Boot 应用中使用时,极大地减少了样板代码(boilerplate code)。
Spring Data JPA 通过提供一个简单的接口
JpaRepository
和一些其他的 CRUD 接口,使开发者可以轻松实现对数据库的基本操作,如增、删、改、查等,而无需编写实现代码。它通过动态代理技术,自动生成实现类,简化了开发过程。核心特性:
-
简化 CRUD 操作:无需编写实现代码,直接通过继承接口来使用常见的数据库操作。
-
基于 JPA:继承了 JPA 的标准特性,如实体类映射、查询方法等。
-
查询方法自动生成:Spring Data JPA 根据方法名自动生成 SQL 查询,无需手写 SQL。
-
分页和排序支持:内置分页、排序功能,支持复杂的查询。
-
-
-
2.2
spring-boot-starter-data-jpa
的作用-
spring-boot-starter-data-jpa
是 Spring Boot 提供的一个启动器(starter),用于集成和配置 Spring Data JPA。在应用中引入该依赖后,Spring Boot 会自动配置与 JPA 相关的 Bean,简化了 JPA 的配置和初始化工作。 -
作用:
-
自动配置数据源(
DataSource
)、JPA 相关的配置(如EntityManagerFactory
)、事务管理器(PlatformTransactionManager
)等。 -
集成常见的 JPA 实现(如 Hibernate),并提供简单的配置方式。
-
支持自动创建数据库表和执行初始化 SQL(根据
spring.jpa.hibernate.ddl-auto
配置项)。 -
提供分页、排序等功能,结合 Spring Data JPA 的接口,可以非常方便地执行复杂查询。
-
-
自动配置:
-
配置数据库连接、实体类管理、事务管理等。
-
使用
JpaRepository
等接口简化持久化操作。
-
-
-
2.3 配置
spring-boot-starter-data-jpa
依赖- 要在 Spring Boot 项目中使用 Spring Data JPA,首先需要在项目的
pom.xml
文件中添加spring-boot-starter-data-jpa
依赖。这个依赖会自动引入 Spring Data JPA 和 Hibernate 等相关库。 - 在
pom.xml
中添加spring-boot-starter-data-jpa
依赖。-
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
-
- 要在 Spring Boot 项目中使用 Spring Data JPA,首先需要在项目的
-
-
3. Spring Boot 和 JPA 整合案例
-
3.1 创建一个基本的 CRUD Web 应用
-
3.2 Spring Boot 集成 JPA 的实践
-
3.2.1 引入基本的 Spring Data JPA 依赖
-
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
-
-
3.2.2 引入数据库连接池(默认使用 HikariCP)推荐默认的就行
-
Spring Boot 默认使用 HikariCP 作为连接池,它不需要额外的依赖。如果你使用的是 HikariCP,你不需要手动添加依赖,因为它已经包含在 Spring Boot 的默认配置中。
-
如果你需要使用其他连接池(例如 DBCP2 或 C3P0),可以选择手动添加相应的依赖:
-
使用 DBCP2 连接池
-
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
-
-
使用 C3P0 连接池
-
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
</dependency>
-
-
-
-
3.2.3 数据库驱动
- 根据你使用的数据库,你需要添加相应的数据库驱动。例如,假设你使用 MySQL,你需要添加 MySQL 驱动:
-
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
-
3.2.4 配置
application.properties
或application.yml
- application.properties
-
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/lirui?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 使用HikariCP作为连接池(Spring Boot默认使用HikariCP)
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
# JPA配置
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
-
- application.yml
-
spring:
datasource:
url: jdbc:mysql://localhost:3306/lirui?useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL5Dialect
hikari:
maximum-pool-size: 10
minimum-idle: 5
-
- application.properties
-
-
-
4. 实体类与数据库表映射
-
4.1 数据库建表语句
-
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
-
-
4.2 创建一个 JPA 实体类
-
package com.lirui.springbootmoduledemo.dao;
import javax.persistence.*;
@Entity // 标识该类为一个 JPA 实体类
@Table(name = "users") // 映射到数据库中的 users 表
public class User {
@Id // 主键标识
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键
@Column(name = "id") // 映射到数据库中的 id 列
private Integer id;
@Column(name = "name", nullable = false, length = 255) // 映射到 name 列
private String name;
@Column(name = "email", nullable = false, length = 255) // 映射到 email 列
private String email;
// Getter 和 Setter 方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
} -
@Entity
:声明User
类是一个 JPA 实体类,Spring Data JPA 会根据该类生成对应的数据库表操作。 -
@Table(name = "users")
:指定实体类对应的数据库表名为users
。如果类名与表名相同,可以省略这个注解。 -
@Id
:标识该字段是实体的主键(id
字段)。 -
@GeneratedValue(strategy = GenerationType.IDENTITY)
:指定主键的生成策略为IDENTITY
,表示使用数据库的自增机制。适用于 MySQL 等数据库。 -
@Column(name = "column_name")
:映射实体类字段到数据库表中的列(如name
、email
)。使用nullable = false
来指定列不允许为NULL
,并且可以设置列的最大长度(如length = 255
)。 -
Integer
类型的id
字段:我们将id
定义为Integer
类型,这样它可以自动与数据库中的int
类型映射。如果你更倾向于使用Long
类型,也可以使用Long
类型。
-
4.2 使用 JPA 的基本类型映射(如:
@Column
,@OneToMany
,@ManyToOne
等)-
JPA 提供了许多注解来描述实体类与数据库表之间的关系,包括对列、主键、关系的映射。
-
4.2.1 @Column
- 映射实体类属性到数据库表的列。
- 可设置属性(如:
nullable
、length
、unique
、columnDefinition
等)。-
nullable
-
定义列是否允许
NULL
值。 -
默认值:
true
(表示列允许为NULL
)。 -
使用场景:如果我们希望某个字段在数据库中不能为空,可以将
nullable
设置为false
,表示该列必须有值。
-
-
length
-
定义字符串类型的列(如
String
)的最大长度。 -
使用场景:主要用于设置数据库中
VARCHAR
类型的字段的最大长度。如果没有显式设置,默认长度为 255。 -
适用类型:
String
、char
和Character
类型。
-
-
unique
-
功能:指定列是否应该是唯一的。
-
默认值:
false
(表示列不要求唯一)。 -
使用场景:如果我们希望某个字段的值在数据库中是唯一的,可以设置
unique = true
,表示该列的值在数据库表中必须是唯一的。
-
-
columnDefinition
-
功能:指定列的具体定义,包括数据类型、默认值、约束等。
-
使用场景:当我们需要对列进行更精细的控制,例如设置数据库列的数据类型、默认值、约束条件等时,可以使用
columnDefinition
。它允许你直接写 SQL 语句来控制列的定义。 -
@Column(columnDefinition = "VARCHAR(100) NOT NULL DEFAULT 'Unknown'")
private String username;
-
-
name
-
定义数据库中列的名称。如果不设置,默认使用字段名。
-
-
insertable
-
指定是否允许在插入时写入该列。默认值是
true
。
-
-
updatable
-
指定是否允许更新该列。默认值是
true
。
-
-
precision
和scale
-
主要用于
BigDecimal
类型,用于定义列的精度和小数位数。
-
-
-
4.2.2 @ManyToOne
和@OneToMany
-
@ManyToOne
:表示多对一的关系。例如,一个用户有多个订单,但每个订单只能属于一个用户。 -
@OneToMany
:表示一对多的关系。例如,一个用户可以有多个订单。 -
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.List;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@OneToMany(mappedBy = "user") // 通过 user 字段映射到 Order
private List<Order> orders; // 一对多关系
// Getter 和 Setter
}import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
@Table(name = "order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String productName;
@ManyToOne // 多对一关系
@JoinColumn(name = "user_id") // 映射外键
private User user; // 每个订单对应一个用户
// Getter 和 Setter
}
-
-
4.2.3 @OneToOne
-
如果实体之间存在一对一关系,可以使用@OneToOne
注解。@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
@OneToOne
@JoinColumn(name = "user_id") // 外键字段
private User user; // 一对一关系
// Getter 和 Setter
}
-
-
4.2.4 @ManyToMany
-
如果两个实体之间存在多对多的关系,可以使用
@ManyToMany
注解。@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(
name = "course_student",
joinColumns = @JoinColumn(name = "course_id"),
inverseJoinColumns = @JoinColumn(name = "student_id")
)
private List<Student> students;
// Getter 和 Setter
}
-
-
-
-
5. Spring Data JPA Repository
-
5.1
JpaRepository
和CrudRepository
接口-
5.1.1
CrudRepository
接口-
CrudRepository
是 Spring Data JPA 提供的基本接口之一,它提供了最基本的 CRUD 操作方法。它是所有 JPA Repository 接口的基础。 -
常用的方法:
-
save(S entity)
:保存实体。 -
findById(ID id)
:根据主键查找实体。 -
findAll()
:查找所有实体。 -
deleteById(ID id)
:根据 ID 删除实体。
-
-
-
5.1.2 JpaRepository
接口(推荐,实现的多)-
JpaRepository
扩展了PagingAndSortingRepository
和CrudRepository
,因此它不仅提供了 CRUD 功能,还支持分页和排序功能。 -
常用的方法:
-
findAll(Pageable pageable)
:分页查询。 -
findAll(Sort sort)
:排序查询。 -
flush()
:刷新持久化上下文。 -
saveAndFlush(S entity)
:保存并立即刷新实体。
-
-
-
-
5.2 创建 Repository 接口
-
Spring Data JPA 中,我们只需要定义一个接口并继承
JpaRepository
或CrudRepository
,Spring 会自动实现所有方法。 -
@Repository // 标记为一个 Spring 的 Repository
public interface UserRepository extends JpaRepository<User, Integer> {
// 可以在这里定义查询方法,例如:
// List<User> findByName(String name);
}
-
-
5.3 常用的 CRUD 操作(保存、查询、删除、更新)
-
@Service // 标注为 Spring 管理的 Service 类
public class UserService {
@Autowired
private UserRepository userRepository; // 注入 UserRepository
// 保存用户
public User saveUser(User user) {
return userRepository.save(user); // 调用 UserRepository 的 save 方法
}
// 获取所有用户
public List<User> getAllUsers() {
return userRepository.findAll(); // 获取所有用户
}
// 根据 ID 查找用户
public Optional<User> getUserById(Integer id) {
return userRepository.findById(id); // 根据 ID 查找用户
}
// 删除用户
public void deleteUser(Integer id) {
userRepository.deleteById(id); // 删除用户
}
}
-
-
5.4 自定义查询方法(如:通过方法名自动生成查询)
-
Spring Data JPA 支持通过方法名自动生成查询。只需要按照一定的规则命名方法,Spring Data JPA 就能自动实现查询。
- 常见的查询方法命名规则:
-
根据属性查找:
findBy<属性名>
例如:findByName(String name)
,表示根据name
属性查找。 -
根据多个属性查找:
findBy<属性1>And<属性2>
例如:findByNameAndEmail(String name, String email)
,表示根据name
和email
属性查找。 -
根据属性模糊查找:
findBy<属性名>Like
例如:findByNameLike(String name)
,表示根据name
属性模糊查找。
-
-
@Repository // 标记为一个 Spring 的 Repository
public interface UserRepository extends JpaRepository<User, Integer> {
// 可以在这里定义查询方法,例如:
List<User> findByName(String name); // 根据名字查询用户
List<User> findByEmail(String email); // 根据 email 查询用户
List<User> findByNameAndEmail(String name, String email); // 根据名字和 email 查询用户
List<User> findByNameLike(String name); // 根据名字模糊查询用户
}
-
-
5.5 使用
@Query
注解编写自定义 SQL 查询-
如果方法名不能满足需求,或者你需要更复杂的查询,可以使用
@Query
注解来编写自定义的 JPQL或者原生 SQL 查询。 -
5.5.1 使用 JPQL(推荐方式)
JPQL 是针对实体对象的查询语言,而不是针对数据库表的 SQL 语言。你可以使用
@Query
注解来编写 JPQL 查询。-
package com.lirui.springbootmoduledemo.repository;
import com.lirui.springbootmoduledemo.dao.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository // 标记为一个 Spring 的 Repository
public interface UserRepository extends JpaRepository<User, Integer> {
// 可以在这里定义查询方法,例如:
@Query("SELECT u FROM User u WHERE u.name = ?1") // JPQL 查询
List<User> findByName(String name); // 根据名字查询用户
List<User> findByEmail(String email); // 根据 email 查询用户
List<User> findByNameAndEmail(String name, String email); // 根据名字和 email 查询用户
List<User> findByNameLike(String name); // 根据名字模糊查询用户
}
-
-
5.5.2 使用原生 SQL
如果你需要直接使用原生 SQL 查询,可以通过
nativeQuery = true
来指定。-
@Query(value = "SELECT * FROM users WHERE email LIKE %?1%", nativeQuery = true) // 原生 SQL 使用 LIKE 查询
List<User> findByEmail(String email); // 根据 email 查询用户
-
-
5.5.3 使用
@Modifying
和@Transactional
进行更新/删除操作-
如果你需要执行更新或删除操作,必须使用
@Modifying
注解,并且方法应该是事务性的。 -
package com.lirui.springbootmoduledemo.repository;
import com.lirui.springbootmoduledemo.dao.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.util.List;
@Repository // 标记为一个 Spring 的 Repository
public interface UserRepository extends JpaRepository<User, Integer> {
// 可以在这里定义查询方法,例如:
@Query("SELECT u FROM User u WHERE u.name = ?1") // JPQL 查询
List<User> findByName(String name); // 根据名字查询用户
@Query(value = "SELECT * FROM users WHERE email LIKE %?1%", nativeQuery = true) // 原生 SQL 使用 LIKE 查询
List<User> findByEmail(String email); // 根据 email 查询用户
List<User> findByNameAndEmail(String name, String email); // 根据名字和 email 查询用户
List<User> findByNameLike(String name); // 根据名字模糊查询用户
@Modifying // 标注为修改操作
@Transactional // 事务支持
@Query("UPDATE User u SET u.name = ?1 WHERE u.id = ?2")
int updateUserNameById(String name, Integer id);
@Modifying
@Transactional
@Query("DELETE FROM User u WHERE u.id = ?1")
void deleteUserById(Integer id);
}
-
-
-
-
6. JPA 查询功能
-
6.1 JPQL查询
- 同上
-
6.2 Criteria API(动态查询)
-
Criteria API 是 JPA 提供的一个用于构建动态查询的 API,它允许我们通过编程方式构造查询,适用于那些查询条件动态变化的情况。使用 Criteria API,可以避免拼接字符串,避免 SQL 注入风险。
-
Criteria API 的常用组件:
-
CriteriaBuilder
:用于创建查询的各种条件和表达式。 -
CriteriaQuery
:表示查询的具体内容。 -
Root
:表示查询的根对象,通常是实体类。 -
Predicate
:表示查询条件。
-
-
package com.lirui.springbootmoduledemo.service;
import com.lirui.springbootmoduledemo.dao.User;
import com.lirui.springbootmoduledemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
import java.util.Optional;
@Service // 标注为 Spring 管理的 Service 类
public class UserService {
@Autowired
private UserRepository userRepository; // 注入 UserRepository
@Autowired
private EntityManager entityManager;
public List<User> findUsersByCriteria(String name, String email) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
Root<User> userRoot = criteriaQuery.from(User.class); // 设置查询根对象
// 构建查询条件
Predicate predicate = criteriaBuilder.conjunction(); // 创建一个“与”的条件
if (name != null) {
predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(userRoot.get("name"), name)); // 添加 name 的条件
}
if (email != null) {
predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(userRoot.get("email"), email)); // 添加 email 的条件
}
criteriaQuery.where(predicate); // 设置查询条件
return entityManager.createQuery(criteriaQuery).getResultList(); // 执行查询
}
// 保存用户
public User saveUser(User user) {
return userRepository.save(user); // 调用 UserRepository 的 save 方法
}
// 获取所有用户
public List<User> getAllUsers() {
return userRepository.findAll(); // 获取所有用户
}
// 根据 ID 查找用户
public Optional<User> getUserById(Integer id) {
return userRepository.findById(id); // 根据 ID 查找用户
}
// 删除用户
public void deleteUser(Integer id) {
userRepository.deleteById(id); // 删除用户
}
}
-
-
6.3 使用 Spring Data JPA 提供的分页与排序功能
-
6.3.1 分页
- Spring Data JPA 为我们提供了
Pageable
接口,用来表示分页请求。Pageable
可以指定页码(page)和每页大小(size)。 -
@Query("SELECT u FROM User u WHERE u.name = ?1") // JPQL 查询
List<User> findByName(String name, Pageable pageable); // 根据名字查询用户public User findByName(User user) {
Pageable pageable = PageRequest.of(0, 10); // 创建 Pageable 实例
List<User> byName = userRepository.findByName(user.getName(), pageable);
return byName.get(0); // 调用 UserRepository 的 save 方法
}
- Spring Data JPA 为我们提供了
-
6.3.2 排序
- 用法一样
-
@Query("SELECT u FROM User u WHERE u.name = ?1") // JPQL 查询
List<User> findByName(String name, Pageable pageable, Sort sort); // 根据名字查询用户public User findByName(User user) {
Pageable pageable = PageRequest.of(0, 10); // 创建 Pageable 实例
Sort sort = Sort.by(Sort.Order.asc("name")); // 根据 name 字段升序排序
List<User> byName = userRepository.findByName(user.getName(), pageable,sort);
return byName.get(0); // 调用 UserRepository 的 save 方法
}
-
-
-
7. 事务管理
-
7.1 什么是事务?
- 事务(Transaction) 是一组操作的集合,这些操作要么全部执行成功,要么在出现问题时全部回滚。事务是数据库管理系统(DBMS)中用于确保数据一致性、完整性、可靠性的一个关键概念。
-
事务的 ACID 特性:
- 原子性(Atomicity):事务中的操作要么全部成功,要么全部失败,不会出现部分成功的情况。
- 一致性(Consistency):事务执行前后,数据库的状态必须是合法的。
- 隔离性(Isolation):一个事务的执行不应该受到其他事务的干扰,事务的执行结果对其他事务是隔离的。
- 持久性(Durability):一旦事务提交,操作的结果会永久保存到数据库中,即使系统崩溃也不会丢失。
-
7.2 Spring 的事务管理基础
-
Spring 提供了两种主要的事务管理方式:
-
声明式事务管理:通过
@Transactional
注解或 AOP 配置来管理事务。 -
编程式事务管理:通过编程方式(即通过
TransactionTemplate
或PlatformTransactionManager
)显式控制事务的开始、提交和回滚。 -
声明式事务管理是 Spring 推荐的事务管理方式,通常使用
@Transactional
注解。
-
-
7.3 使用
@Transactional
注解-
Spring 的
@Transactional
注解可以用来声明式地管理事务。通过将其应用于方法或类上,Spring 会自动在方法执行时开启事务,方法执行结束时提交事务,若方法抛出异常则回滚事务。基本使用
-
应用于类:应用于类级别时,类中的所有方法都会被事务管理。
-
应用于方法:应用于方法时,只有该方法会被事务管理。
-
-
@Transactional
常用属性:-
propagation
:定义事务的传播行为(如如何处理事务的嵌套)。 -
isolation
:定义事务的隔离级别(如多个事务之间如何隔离)。 -
rollbackFor
:指定哪些异常会导致事务回滚。 -
noRollbackFor
:指定哪些异常不会导致事务回滚。 -
timeout
:指定事务的超时时间(单位:秒)。 -
readOnly
:设置事务是否为只读事务,优化数据库性能(对于只读取数据的操作)。 -
value
:指定事务管理器的名字,默认情况下 Spring 会使用默认的事务管理器。
-
-
-
7.4 事务的传播行为和隔离级别
-
事务传播行为(Propagation)
-
事务传播行为定义了一个事务方法如何与另一个事务方法交互。Spring 支持以下几种传播行为:
-
REQUIRED
(默认值):如果当前没有事务,则创建一个新的事务。如果当前已经存在事务,当前方法将加入到这个事务中。 -
REQUIRES_NEW
:无论当前是否存在事务,都会创建一个新的事务。如果当前有事务,则会暂停当前事务。 -
SUPPORTS
:如果当前有事务,则加入事务。如果没有事务,则以非事务的方式执行。 -
NOT_SUPPORTED
:如果当前有事务,则将事务挂起,并以非事务方式执行。 -
MANDATORY
:当前必须有事务。如果当前没有事务,则抛出异常。 -
NEVER
:当前不能有事务。如果当前有事务,则抛出异常。 -
NESTED
:如果当前没有事务,则创建一个新的事务。如果当前有事务,则创建一个嵌套事务。嵌套事务的提交与回滚会独立于外部事务。
-
-
-
事务隔离级别(Isolation)
-
事务隔离级别定义了不同事务之间如何隔离。Spring 支持以下几种隔离级别:
-
READ_UNCOMMITTED
:允许读取未提交的数据,可能导致脏读、不可重复读、幻读问题。 -
READ_COMMITTED
:只能读取已经提交的数据,避免脏读,但可能会有不可重复读和幻读。 -
REPEATABLE_READ
:读取的是一致的数据,避免脏读和不可重复读,但可能会有幻读问题。 -
SERIALIZABLE
:强制事务串行化,避免脏读、不可重复读和幻读,但性能开销较大。
-
-
-
-
7.5 事务回滚机制
-
Spring 的事务回滚机制允许我们控制事务在出现异常时是否回滚。默认情况下,Spring 仅在遇到 运行时异常(
RuntimeException
) 或 错误(Error
) 时回滚事务。 -
默认回滚规则:
-
回滚事务:遇到
RuntimeException
或Error
。 -
不回滚事务:遇到
checked exceptions
(检查型异常)。
-
-
-
-
8. 配置与优化
-
8.1 配置数据源(
DataSource
)-
如果你使用的是关系型数据库(如 MySQL、PostgreSQL、H2 等),Spring Boot 会自动配置数据源。
例如,对于 MySQL,Spring Boot 会自动使用
HikariCP
(Spring Boot 默认的数据源连接池)来管理连接池。
-
-
8.2 使用
application.properties
配置数据库连接池-
Spring Boot 默认使用
HikariCP
作为连接池,它是一个高性能的 JDBC 连接池,可以有效地管理数据库连接。在application.properties
文件中,可以配置数据库连接池的相关属性。 -
配置连接池的基本参数
-
# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 连接池配置
spring.datasource.hikari.maximum-pool-size=20 # 最大连接池大小
spring.datasource.hikari.minimum-idle=5 # 最小空闲连接数
spring.datasource.hikari.idle-timeout=600000 # 空闲连接超时时间(毫秒)
spring.datasource.hikari.max-lifetime=1800000 # 连接最大生命周期(毫秒)
spring.datasource.hikari.connection-timeout=30000 # 连接超时时间(毫秒)
-
-
配置其他连接池特性
-
spring.datasource.hikari.auto-commit=true # 自动提交事务
spring.datasource.hikari.connection-test-query=SELECT 1 # 检测连接是否有效的查询语句
spring.datasource.hikari.pool-name=HikariCP # 连接池名称
spring.datasource.hikari.leak-detection-threshold=15000 # 设置连接泄露检测时间(毫秒)
-
-
配置连接池性能优化
-
spring.datasource.hikari.maximum-pool-size
:控制最大连接数。根据业务量进行调整,过大或过小都会影响性能。 -
spring.datasource.hikari.minimum-idle
:空闲连接数,设置为空闲连接池的最小值。可以帮助快速响应查询请求。 -
spring.datasource.hikari.idle-timeout
:空闲连接超时时间,当连接池中的连接空闲时间超过此值时,将被销毁。 -
spring.datasource.hikari.max-lifetime
:连接最大生命周期,当连接池中的连接达到此最大生命周期时,它们将被销毁并重新创建。
-
-
-
8.3 配置 JPA 的 Hibernate 属性(如:DDL 自动生成策略、SQL 日志输出等)
-
8.3.1 配置 Hibernate 的 DDL 自动生成策略
-
spring.jpa.hibernate.ddl-auto
:控制 Hibernate 如何自动管理数据库模式。 -
常见的值包括:
-
none
:不进行任何操作,数据库架构由外部管理。 -
update
:Hibernate 会根据实体类的变更自动更新数据库架构。 -
create
:每次应用启动时都会创建数据库架构。 -
create-drop
:在应用启动时创建架构,并在应用关闭时删除架构。-
spring.jpa.hibernate.ddl-auto=update
-
-
-
-
8.3.2 配置 Hibernate 的 SQL 日志输出
-
spring.jpa.show-sql
:控制是否输出 SQL 语句。 -
spring.jpa.properties.hibernate.format_sql
:格式化 SQL,使其更易读。 -
spring.jpa.properties.hibernate.use_sql_comments
:是否输出 SQL 注释,帮助理解 SQL 执行过程。-
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
-
-
-
-