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

相关推荐
JH30738 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
qq_124987075311 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_12 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_8187320612 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu15 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶15 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip16 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide17 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf17 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva17 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端