在Spring Boot项目中选择持久层方案时,多数人会立刻想到JPA或MyBatis,其实Spring Data JDBC是一个经常被低估的选择。它去掉了JPA中复杂的持久化上下文、懒加载和一级缓存等概念,采用直接加载、直接保存的设计哲学,让对象关系映射回归简单。本文将完整讲解如何在Spring Boot中整合Spring Data JDBC,并深入剖析其核心用法与注意事项。

一、Spring Data JDBC是什么,它与其他持久层框架有何区别
Spring Data JDBC是Spring Data项目的一个子模块,底层基于Spring Framework提供的JdbcTemplate构建。它的设计目标是提供一种"简化版的ORM",既保留关系型数据库的直观性,又能像Spring Data JPA那样通过接口方法名自动生成SQL。与JPA最大的不同在于,Spring Data JDBC没有持久化上下文,对象被加载后就是普通的POJO,保存时会将整个对象完整写入数据库,而不是计算增量变更。
与MyBatis相比,Spring Data JDBC省去了编写XML映射文件的繁琐,简单的增删改查直接由框架生成SQL,复杂的查询可以通过@Query注解书写SQL语句。它的聚合根设计思想也值得注意:一个实体如果实现了AggregateRoot接口,或者被注册为聚合根,保存时框架会级联处理其子对象,并在删除时自动清理关联数据。这种模型非常适合领域驱动设计(DDD)风格的微服务项目。
总结一下三者的特点:JPA功能最全但概念复杂,适合对象模型与数据库表高度一致的传统应用;MyBatis灵活可控,适合SQL调优要求高的场景;Spring Data JDBC轻量直接,适合追求简单、希望对数据库行为有清晰预期的团队。
二、整合步骤详解:从依赖配置到实体映射
第一步是引入依赖。在pom.xml中添加spring-boot-starter-data-jdbc和数据库驱动,这里以MySQL为例。注意不需要再引入spring-boot-starter-jdbc,前者已经包含所需的核心类。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>第二步是配置数据源。在application.yml中书写数据库连接信息,同时建议开启SQL日志方便调试:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
data:
jdbc:
repositories:
enabled: true
logging:
level:
org.springframework.jdbc.core: debug第三步是定义实体类。Spring Data JDBC默认使用驼峰转下划线的命名策略,例如createTime字段会映射到create_time列。主键使用@Id标注,如果数据库采用自增策略,还需要加上@Version或依赖框架对null主键的判断逻辑,自增主键在保存后会自动回填到实体中。
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import java.time.LocalDateTime;
@Table("t_user")
public class User {
@Id
private Long id;
private String username;
private String email;
private Integer age;
private LocalDateTime createTime;
// 省略getter和setter
}三、Repository的使用方法与自定义查询
Spring Data JDBC的Repository用法与JPA高度一致,只需定义一个接口继承CrudRepository,并注入使用即可。框架会在启动时通过动态代理生成实现类,方法名遵循相同的派生查询规则,例如findByUsernameAndAgeGreaterThan会自动翻译成对应的WHERE条件。
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUsername(String username);
List<User> findByAgeGreaterThan(Integer age);
long countByCreateTimeAfter(LocalDateTime time);
}对于复杂查询,方法名派生会显得冗长且不易读,这时可以使用@Query注解直接书写SQL。注意Spring Data JDBC使用的是原生SQL而非JPQL,参数同样通过占位符绑定:
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface UserRepository extends CrudRepository<User, Long> {
@Query("SELECT * FROM t_user WHERE age BETWEEN :min AND :max ORDER BY age")
List<User> findByAgeRange(@Param("min") Integer min, @Param("max") Integer max);
}在Service层使用时,直接通过构造器注入Repository即可完成常规操作。保存方法统一为save,当主键为null时执行INSERT,主键有值时执行UPDATE。删除支持按实体或按ID两种方式。
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public User createUser(User user) {
user.setCreateTime(LocalDateTime.now());
return userRepository.save(user);
}
public List<User> listAdults() {
return userRepository.findByAgeGreaterThan(17);
}
}四、进阶技巧:乐观锁、分页与常见坑点
Spring Data JDBC原生支持乐观锁,只需在实体中添加一个@Version标注的字段,每次UPDATE时框架会自动将版本号加一,并在WHERE条件中校验旧版本。当并发修改导致版本不匹配时,更新会影响零行,框架抛出OptimisticLockingFailureException,可以在业务层捕获后重试。
@Table("t_user")
public class User {
@Id
private Long id;
@Version
private Long version; // 数据库中对应version列,默认值为0
// 其他字段
}分页方面,可以让Repository额外继承PagingAndSortingRepository,或者直接让方法返回Page<T>并传入Pageable参数。需要注意的是,Spring Data JDBC对Page<T>返回类型的支持依赖版本,较老版本可能需要手动计算总数,建议升级到较新的版本使用。
最后提醒几个容易踩的坑:其一,Spring Data JDBC没有懒加载,聚合根一查出来所有子对象都会被加载,关联数据量大时要注意性能;其二,save保存聚合根时会全量更新所有字段,未赋值的字段会被写为null,因此更新前最好先查询再修改;其三,跨聚合的关联应只存ID而不是对象引用,这符合DDD的最佳实践,也能避免意外的级联删除。
总体而言,Spring Data JDBC以极低的入门成本提供了完整的持久层能力,尤其适合中小型项目或对JPA复杂度感到疲惫的团队。如果你的项目正在寻找一种SQL清晰、心智负担小的数据访问方案,不妨动手试试它。
Spring BootSpring Data JDBCJDBC整合修改时间:2026-09-02 20:53:06