📚 总览:Spring Boot 如何与 SQL 数据库交互?
Spring Boot 提供了多层次的支持来操作数据库:
层次 | 技术 | 特点 |
---|---|---|
最底层 | JdbcTemplate |
直接执行 SQL,轻量高效 |
中间层 | JPA + Hibernate | 面向对象映射,自动建表 |
高层抽象 | Spring Data JPA / JDBC / R2DBC | 接口即实现,方法名生成 SQL |
响应式 | R2DBC | 非阻塞、异步数据库访问 |
工具支持 | H2 Console、jOOQ | 可视化调试、类型安全查询 |
🔧 5.11.1 配置数据源(DataSource)
✅ 什么是 DataSource
?
Java 标准接口 javax.sql.DataSource
,用于获取数据库连接。Spring Boot 会自动帮你创建这个对象。
📦 内嵌数据库(Embedded Database)
开发时很方便,比如 H2、HSQL、Derby,数据在内存中,重启就没了。
- Spring Boot 能自动配置 H2、HSQL、Derby。
- 只需添加依赖即可,不需要写 URL。
- 示例:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
⚠️ 注意:测试中多个上下文可能共用一个内嵌数据库,若要隔离,设置:
properties
spring.datasource.generate-unique-name=true
❗ 关闭自动关闭(防止 Spring 还没用完就被关了):
- H2:
DB_CLOSE_ON_EXIT=FALSE
- HSQL: 不要用
shutdown=true
🏭 生产环境数据库(Pooling DataSource)
Spring Boot 自动选择连接池(按优先级):
- HikariCP ✅(首选,性能最好)
- Tomcat JDBC Pool
- Commons DBCP2
只要引入 spring-boot-starter-jdbc
或 spring-boot-starter-data-jpa
,就会自动带上 HikariCP。
你可以手动指定连接池类型:
properties
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
💡 如果你自己定义了
@Bean DataSource
,Spring Boot 就不再自动配置。
🛠 配置 DataSource 的方式
通过 application.properties
设置:
properties
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
✅ 提示:
driver-class-name
通常可以省略,Spring Boot 会根据 URL 自动推断(如jdbc:mysql://...
→ MySQL 驱动)。
⚙️ 自定义连接池参数(以 Hikari 为例)
properties
# Hikari 特有配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000
# Tomcat Pool 示例(文档中的例子)
spring.datasource.tomcat.max-wait=10000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.test-on-borrow=true
🌐 使用 JNDI 数据源(部署到应用服务器时)
如果你把应用部署到 WebLogic、JBoss 等容器,数据库由容器管理,可通过 JNDI 获取:
properties
spring.datasource.jndi-name=java:jboss/datasources/customers
此时就不需要 url/username/password
。
🛠 5.11.2 使用 JdbcTemplate
Spring 的 JdbcTemplate
是最基础的 JDBC 操作工具,Spring Boot 会自动配置它。
✅ 使用方法
java
@Component
public class MyBean {
private final JdbcTemplate jdbcTemplate;
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<String> getAllUsernames() {
return jdbcTemplate.queryForList(
"SELECT username FROM users", String.class);
}
}
✅ 构造器注入(推荐),无需
@Autowired
(Spring 4.3+ 自动装配)
🎛 自定义模板行为
properties
spring.jdbc.template.max-rows=500
🧱 5.11.3 JPA 和 Spring Data JPA
📌 什么是 JPA?
Java Persistence API,标准 ORM 技术,把 Java 对象"映射"成数据库表。
常用实现:Hibernate
🚀 快速开始依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
包含:
- Hibernate(JPA 实现)
- Spring Data JPA(简化 Repository)
- Spring ORM(核心支持)
🏗 实体类(Entity Classes)
以前要用 persistence.xml
,现在 Spring Boot 自动扫描 @Entity
类。
java
@Entity
public class City implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
private String state;
protected City() {} // JPA 要求无参构造
public City(String name, String state) {
this.name = name;
this.state = state;
}
// getter/setter...
}
✅ 默认扫描主类所在包及其子包。可用
@EntityScan("com.example.domain")
修改扫描路径。
🗃 Spring Data JPA Repositories
你只需定义接口,Spring Data 自动实现!
java
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
City findByNameAndStateAllIgnoringCase(String name, String state);
}
- 方法名自动解析成 SQL 查询。
find...By...
是命名规则。- 支持分页
Pageable
。
✅ 推荐继承
CrudRepository
或JpaRepository
,功能更全(增删改查、批量等)。
java
public interface CityRepository extends JpaRepository<City, Long> {
// 自动有 save(), findById(), deleteById(), findAll()...
}
🔁 启动模式(Bootstrap Mode)
控制 Repository 初始化时机:
properties
# 默认:启动时初始化
spring.data.jpa.repositories.bootstrap-mode=default
# 延迟初始化(适合微服务注册前不连 DB)
spring.data.jpa.repositories.bootstrap-mode=deferred
# 懒加载
spring.data.jpa.repositories.bootstrap-mode=lazy
⚠️ 延迟/懒加载时,确保不要在启动初期访问数据库。
🔧 创建/删除数据库表(DDL)
默认只在使用内嵌数据库时自动建表。
想手动控制建表行为,使用:
properties
# 常见选项:
spring.jpa.hibernate.ddl-auto=none # 不做任何操作(生产推荐)
spring.jpa.hibernate.ddl-auto=create # 启动时创建表(丢失旧数据)
spring.jpa.hibernate.ddl-auto=create-drop # 启动创建,关闭删除
spring.jpa.hibernate.ddl-auto=update # 更新表结构(慎用)
spring.jpa.hibernate.ddl-auto=validate # 校验实体与表是否一致
⚠️ 生产环境必须设为
none
或validate
,避免误删数据!
也可以设置其他 Hibernate 属性:
properties
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
👁 Open EntityManager in View
Web 项目中,默认开启 OpenEntityManagerInViewInterceptor
,允许在视图层(如 Thymeleaf)进行懒加载。
但可能导致 N+1 查询问题或事务过长。
关闭它:
properties
spring.jpa.open-in-view=false
✅ 推荐在生产环境中关闭,避免性能问题。
🔄 5.11.4 Spring Data JDBC
轻量级 ORM,比 JPA 简单,适合简单场景。
- 不支持延迟加载、缓存等复杂特性。
- 但更直观,性能好。
引入依赖即可:
xml
<dependency>
<groupId>spring-boot-starter-data-jdbc</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
用法类似 Spring Data JPA:
java
public interface CityRepository extends CrudRepository<City, Long> {
List<City> findByState(String state);
}
✅ 自动根据方法名生成 SQL。
🔍 5.11.5 使用 H2 Web 控制台
开发时非常有用的数据库可视化工具。
✅ 开启条件:
- 是 Web 应用(有 spring-web)
- 有
h2
依赖 - 启用了
spring-boot-devtools
满足后访问:http://localhost:8080/h2-console
⚠️ 默认路径
/h2-console
,可修改:
properties
spring.h2.console.path=/console
❗ 绝对不要在生产环境开启!
properties
spring.h2.console.enabled=true # 仅开发用
🧩 5.11.6 使用 jOOQ(类型安全 SQL)
jOOQ 是一个生成 Java 代码的工具,让你用链式语法写 SQL,且编译时检查错误。
✅ 使用步骤:
- 添加依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
-
用
jooq-codegen-maven
插件生成代码(根据数据库表生成 Java 类) -
使用
DSLContext
构建类型安全查询:
java
@Autowired
private DSLContext dsl;
public List<Author> findAuthorsBornAfter1980() {
return dsl.selectFrom(AUTHOR)
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(Date.valueOf("1980-01-01")))
.fetchInto(Author.class);
}
✅ 类型安全、IDE 提示、防 SQL 注入。
🌐 SQL 方言(Dialect)
properties
spring.jooq.sql-dialect=POSTGRES
如果不设置,Spring Boot 自动检测。
🛠 高级定制 jOOQ 行为
可以注入以下组件进行定制:
ConnectionProvider
TransactionProvider
Settings
ExecuteListenerProvider
(监听 SQL 执行)
⚡ 5.11.7 使用 R2DBC(响应式数据库)
用于响应式编程(Reactor),非阻塞 IO。
✅ 适用场景:
- 高并发、低延迟系统
- 使用 WebFlux 的项目
📦 依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
🛠 配置:
properties
spring.r2dbc.url=r2dbc:postgresql://localhost/test
spring.r2dbc.username=dbuser
spring.r2dbc.password=dbpass
✅ 不需要 driver-class-name,R2DBC 自动发现驱动。
🧩 内嵌数据库支持
xml
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>runtime</scope>
</dependency>
自动配置,无需 URL。
🧰 使用 DatabaseClient
Spring Data 提供的响应式数据库客户端:
java
@Autowired
private DatabaseClient client;
public Mono<City> findCity(String name) {
return client.sql("SELECT * FROM city WHERE name = $1")
.bind(0, name)
.fetch()
.one();
}
🗃 Spring Data R2DBC Repositories
和 JPA 类似,但返回 Mono<T>
或 Flux<T>
:
java
public interface CityRepository extends ReactiveCrudRepository<City, Long> {
Mono<City> findByNameAndStateAllIgnoringCase(String name, String state);
}
✅ 方法名自动解析成查询,支持响应式流。
✅ 总结:如何选择技术?
需求 | 推荐技术 |
---|---|
简单 CRUD,快速开发 | ✅ Spring Data JPA |
高性能、轻量级 | ✅ JdbcTemplate 或 Spring Data JDBC |
类型安全 SQL 查询 | ✅ jOOQ |
响应式系统(WebFlux) | ✅ R2DBC + Spring Data R2DBC |
开发调试 | ✅ H2 + H2 Console |
复杂 SQL、报表 | ✅ JdbcTemplate + 原生 SQL 或 jOOQ |
📌 最佳实践建议
- 生产环境不要用
ddl-auto=create-drop
- 关闭
open-in-view
,避免懒加载陷阱 - H2 Console 仅开发启用
- 优先使用构造器注入
- Repository 接口继承
JpaRepository
而不是Repository
- R2DBC 和 JDBC 不要混用在一个应用中(除非明确知道风险)
如果你想深入了解某一部分(比如"如何用 jOOQ 生成代码"或"R2DBC 如何做事务"),我可以继续展开讲解。是否需要?