文章目录

前言
Spring Data JPA 是 Spring 生态中用于简化 Java 持久层开发 的ORM框架,它基于 JPA 规范(如 Hibernate 是 JPA 的主流实现),通过 约定优于配置 的设计,大幅减少数据访问层(DAO)的模板代码,让开发者专注于业务逻辑而非数据操作细节。
JPA、Hibernate、Spring data jpa之间的关系
- JPA(Java Persistence API):是 Java EE 定义的 持久层规范(接口集合),规定了对象 - 关系映射(ORM)、实体管理、查询等核心能力,本身不包含实现。
- Hibernate:是 JPA 规范的 主流实现框架(即 "落地代码"),提供了 JPA 接口的具体实现,同时扩展了更多功能(如二级缓存、复杂查询)。
- Spring Data JPA:是 JPA 的 "封装增强层",它基于 JPA 规范,通过抽象封装,进一步简化 DAO 层代码(如无需手动实现 findById、findAll 等基础方法),同时兼容所有 JPA 实现(默认集成 Hibernate)。
三者关系可类比为:JPA(接口规范) ← Hibernate(实现) ← Spring Data JPA(简化封装)
核心接口
Spring Data JPA 定义了 Repository 系列接口,开发者只需 定义接口并继承,无需手动实现方法,框架会自动生成代理对象和 SQL。
核心接口继承关系:
xml
Repository(顶层接口,空接口,标记作用)
├─ CrudRepository(提供 CRUD 基础操作:save、findById、delete 等)
│ └─ PagingAndSortingRepository(扩展分页和排序:findAll(Pageable)、findAll(Sort))
│ └─ JpaRepository(进一步扩展:flush、saveAndFlush、deleteInBatch 等)
└─ JpaSpecificationExecutor(支持动态条件查询,需手动继承)
入门案例
案例中使用jpa完成基本的增删改查
JDK版本:jdk17
数据库表
sql
CREATE TABLE `goods` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`number` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `goods` VALUES (1, '苹果', 2);
INSERT INTO `goods` VALUES (2, '香蕉', 5);
INSERT INTO `goods` VALUES (3, '橘子', 3);
INSERT INTO `goods` VALUES (6, '草莓', 1);
INSERT INTO `goods` VALUES (7, '西瓜', 1);
pom.xml
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>jpa-test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jpa-test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>annotationProcessor</scope>
</dependency>
<!-- mysql JDBC -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 添加JPA依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.22</version>
</dependency>
</dependencies>
相关配置
application.yml
yml
server:
port: 8080
spring:
application:
name: jpa-test
datasource:
type: com.alibaba.druid.pool.DruidDataSource
name: test
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
# 连接池配置
initialSize: 2
minIdle: 30
maxActive: 50
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 30000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: true
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
jpa:
# 配置 DBMS 类型
database: MYSQL
# 配置是否将执行的 SQL 输出到日志
show-sql: true
properties:
hibernate:
format_sql: true
jdbc:
batch_size: 500
主启动类
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EnableJpaRepositories(value = {"com.qf"})
@EntityScan(value = {"com.qf"})
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
}
实体类
java
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Table
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
@Id
@GeneratedValue(
strategy = GenerationType.IDENTITY
)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "number")
private Integer number;
}
mapper
java
import com.qf.entity.Goods;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author qibaohai
* @version 1.0
* @data 2025/10/9 19:51
*/
public interface GoodsMapper extends JpaRepository<Goods, Long>, JpaSpecificationExecutor<Goods> {
@Query(value = "select s from Goods s where s.name = ?1")
List<Goods> getByName(String name);
}
server
java
import com.qf.entity.Goods;
import org.springframework.data.domain.Page;
import java.util.List;
import java.util.Map;
/**
* @author qixiansheng
* @version 1.0
* @data 2025/10/9 21:28
*/
public interface GoodsService {
List<Goods> getList();
Page<Goods> getPage(Map<String,Object> map);
Goods getById(Long id);
List<Goods> getByName(String name);
Long add(Goods goods);
Boolean update(Goods goods);
Boolean deleteById(Long id);
}
java
import com.qf.entity.Goods;
import com.qf.mapper.GoodsMapper;
import com.qf.server.GoodsService;
import jakarta.persistence.criteria.Predicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* @author qixiansheng
* @version 1.0
* @data 2025/10/9 21:28
*/
@Service
public class GoodsServiceImpl implements GoodsService {
@Autowired
private GoodsMapper goodsMapper;
@Override
public List<Goods> getList() {
//select * from goods s
// List<Goods> result = goodsMapper.findAll();
//select * from goods s where s.number = 1
Goods goods = new Goods();
goods.setNumber(1);
List<Goods> result = goodsMapper.findAll(Example.of(goods));
return result;
}
@Override
public Page<Goods> getPage(Map<String,Object> map) {
Sort sort = Sort.by(Sort.Direction.ASC,
"number",
"name");
Integer currentPage = Integer.parseInt((String) map.get("currentPage"));
Integer pageSize = Integer.parseInt((String) map.get("pageSize"));
Pageable pageable = PageRequest.of(currentPage - 1, pageSize, sort);
// 构建动态查询条件
Specification<Goods> spe = (root, query, builder) -> {
Predicate predicate = builder.conjunction();
// ID精确匹配(如果存在)
if (map.get("id") != null) {
predicate = builder.and(predicate,
builder.equal(root.get("id"), map.get("id")));
}
// 名称模糊查询(如果存在)
if (map.get("name") != null) {
predicate = builder.and(predicate,
builder.like(root.get("name"), "%" + map.get("name") + "%"));
}
// number精确匹配(如果存在)
if (map.get("number") != null) {
predicate = builder.and(predicate,
builder.equal(root.get("number"), map.get("number")));
}
return predicate;
};
Page<Goods> page = goodsMapper.findAll(spe, pageable);
return page;
}
@Override
public Goods getById(Long id) {
return goodsMapper.getById(id);
}
@Override
public List<Goods> getByName(String name) {
return goodsMapper.getByName(name);
}
@Override
public Long add(Goods goods) {
Goods data = goodsMapper.save(goods);
return data.getId();
}
@Override
public Boolean update(Goods goods) {
Goods data = goodsMapper.save(goods);
return true;
}
@Override
public Boolean deleteById(Long id) {
goodsMapper.deleteById(id);
return true;
}
}
Controller
java
import com.qf.entity.Goods;
import com.qf.server.GoodsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* @author qibaohai
* @version 1.0
* @data 2025/10/9 19:52
*/
@RestController
@RequestMapping("/goods")
@Slf4j
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/getList")
public String getList() {
List<Goods> result = goodsService.getList();
return result.toString();
}
@GetMapping("/getPage")
public String getPage(@RequestParam Map<String,Object> map) {
Page<Goods> result = goodsService.getPage(map);
return result.getContent().toString();
}
@GetMapping("/getById")
public String getById(@RequestParam("id") Long id) {
Goods result = goodsService.getById(id);
return result.toString();
}
@GetMapping("/getByName")
public String getByName(@RequestParam("name") String name) {
List<Goods> result = goodsService.getByName(name);
return result.toString();
}
@PostMapping("/add")
public String add(@RequestBody Goods goods) {
Long result = goodsService.add(goods);
return result + "";
}
@PostMapping("/update")
public String update(@RequestBody Goods goods) {
Boolean result = goodsService.update(goods);
return result.toString();
}
@PostMapping("/deleteById")
public String deleteById(@RequestParam("id") Long id) {
Boolean result = goodsService.deleteById(id);
return result.toString();
}
}