Spring Data JPA快速入门

文章目录


前言

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();
    }
}

相关推荐
while(1){yan}1 分钟前
拦截器(详解)
数据库·spring boot·spring·java-ee·拦截器
柒.梧.5 分钟前
Spring Boot集成JWT Token实现认证授权完整实践
java·spring boot·后端
indexsunny41 分钟前
互联网大厂Java面试实战:基于电商场景的Spring Boot与微服务技术问答
java·spring boot·微服务·面试·hibernate·电商场景·技术问答
内存不泄露41 分钟前
基于Spring Boot和Vue 3的智能心理健康咨询平台设计与实现
vue.js·spring boot·后端
qq_124987075342 分钟前
基于Spring Boot的电影票网上购票系统的设计与实现(源码+论文+部署+安装)
java·大数据·spring boot·后端·spring·毕业设计·计算机毕业设计
麦兜*1 小时前
【Spring Boot】 接口性能优化“十板斧”:从数据库连接到 JVM 调优的全链路提升
java·大数据·数据库·spring boot·后端·spring cloud·性能优化
蛐蛐蜉蝣耶1 小时前
Spring Boot实现DynamicMethodMatcherPointcut示例
java·spring boot·后端
码农小卡拉1 小时前
Springboot “钩子”:@PostConstruct注解
java·spring boot·后端·spring·spring cloud
奔波霸的伶俐虫1 小时前
spring boot集成kafka学习
spring boot·学习·kafka
内存不泄露1 小时前
基于Spring Boot和Vue的在线考试系统设计与实现
vue.js·spring boot·后端