☰
Spring Boot数据库配置全解析:从单数据源到连接池与多数据源
2026/10/7 5:14:52 网站建设 项目流程

1. 别急着写代码,先把“数据库连接”这件事想清楚

很多同学拿到 Spring Boot 项目,第一件事就是往application.yml里塞数据库地址、用户名、密码,然后启动,报错,改配置,再启动,再报错。折腾一上午,最后发现是驱动依赖没加,或者时区参数写错。说实话,这些坑我当年全踩过,所以这篇东西我不打算只贴一份配置模板,而是把“在 Spring Boot 里配置数据库”这件事的前因后果、常见思路、实操细节和排查方法一次讲透,希望能帮你少走几周弯路。

先明确核心关键词:Spring Boot、配置、数据库。你要知道,Spring Boot 之所以能“自动配置”数据库,核心机制是spring.factories和@EnableAutoConfiguration。但这套机制并不是玄学,它背后就是“约定优于配置”的思想——你只要在配置文件里给出连接信息,Spring Boot 就自动帮你创建数据源、会话工厂、事务管理器。真正的问题在于:你需要理解它默认做了什么、你覆盖了什么、什么时候该用多数据源、什么时候该引入连接池。

这篇文章适合谁?刚接触 Spring Boot 的初学者、从 SSM 项目转到 Spring Boot 的老手、以及想搞懂“为什么改配置没用”的排查党。我会从最基础的单一数据源配置讲起,再逐步深入到多数据源、连接池参数调优、常见报错排查,最后给出一套我在生产环境里验证过的配置参考。

2. 第一个层面的配置:单一数据源,你只需要这三样东西

2.1 添加依赖,这一步错了后面全白搭

配置数据库之前,先把pom.xml的依赖加对。我见过太多人只加了spring-boot-starter-web,然后抱怨“为什么我配置了数据库但是连不上?”——因为你根本没引入 JDBC 相关依赖。

以 MySQL 为例,至少需要这两个依赖:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>

如果你用 MyBatis,那就把spring-boot-starter-jdbc换成mybatis-spring-boot-starter(注意版本要和 Spring Boot 版本匹配)。用 JPA 的话,就引入spring-boot-starter-data-jpa。这三个依赖不要重复加,否则可能出现 Bean 冲突。

注意:MySQL 8.x 的驱动类名是com.mysql.cj.jdbc.Driver,MySQL 5.x 是com.mysql.jdbc.Driver。如果你还在用旧驱动连新版 MySQL,大概率会报ClassNotFoundException或者时区异常。另外,从 Spring Boot 2.7.5 开始,官方推荐mysql-connector-j而非mysql-connector-java,别搞混了。

2.2 配置文件里的几个关键参数,逐字拆解

依赖加好之后,在application.yml里写数据库配置。以下是一份我常用的基础配置:

spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/my_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: 123456

这里面有几个参数容易被忽略,但特别重要:

  • driver-class-name:驱动类名,必须和依赖里的驱动版本对应。
  • url里的useSSL=false:本地开发时建议关掉 SSL,否则 MySQL 8 默认开启 SSL 会导致连接警告或失败。
  • serverTimezone=Asia/Shanghai:不设置这个,你可能会遇到“数据库连接失败:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized”这种乱码报错。
  • allowPublicKeyRetrieval=true:如果 MySQL 8 使用caching_sha2_password认证插件,连接工具或驱动可能需要这个参数,否则可能报Public Key Retrieval is not allowed。

我建议把&allowPublicKeyRetrieval=true这个参数加上,尤其在用 Docker 启动 MySQL 8 的环境里,它能省去很多莫名其妙的连接问题。

2.3 连接池:HikariCP 才是默认王者

Spring Boot 2.x 开始,默认的连接池就是 HikariCP。你可以什么都不配,它也能跑,但生产环境我建议至少把下面几个参数显式写出来:

spring: datasource: hikari: minimum-idle: 5 maximum-pool-size: 20 idle-timeout: 300000 connection-timeout: 20000 max-lifetime: 1800000 pool-name: MyHikariPool

这些参数的含义不需要死记,但建议理解两个:

  • maximum-pool-size:最大连接数。别以为越大越好,MySQL 默认连接上限是 151(可以用show variables like 'max_connections'查看),如果你把连接池调到 200,数据库直接拒绝连接。
  • max-lifetime:连接的最大存活时间。MySQL 默认wait_timeout是 8 小时,如果连接池里的连接存活时间比数据库的 wait_timeout 长,就会出现“连接被数据库关闭,但连接池不知道,还在用”的情况,报错通常是Communications link failure。把max-lifetime调成小于数据库wait_timeout的值就能规避。

实操心得:我在一次压测中遇到过奇怪现象,接口偶尔第一次调用超时,第二次就正常。排查半天发现是 HikariCP 初始化时懒加载连接,首请求需要额外时间建立连接。解决办法是启动时加一个预热请求,或者把initialization-fail-timeout调大。

3. 第二层面:配置不生效?检查你的自动配置和优先级

3.1 为什么改了application.yml却还是连的旧库?

这是新手最容易懵的问题。明明把application.yml里的 url 改成了新数据库地址,重启之后发现还是连的旧库。原因往往是这几个:

  • 项目里有多个配置文件:application.yml、application-dev.yml、application-prod.yml,而且你启动时激活的是别的 profile。
  • 环境变量或启动参数覆盖了配置文件里的值。Spring Boot 的配置优先级是:命令行参数 > Java 系统属性 > 环境变量 >application-{profile}.yml>application.yml。如果你的服务器上设置了SPRING_DATASOURCE_URL环境变量,那么在application.yml里写什么都没用。
  • target目录下有陈旧的编译产物,比如旧的application.yml被复制过去了,而你改的是src/main/resources下的文件。这种情况下 clean 一下项目再重启。

排查方法很简单,启动时加参数--debug或者--trace,可以打印自动配置报告,其中会告诉你当前生效的条件和配置来源。也可以直接访问http://localhost:8080/actuator/env(要引入 actuator 依赖),看看当前生效的spring.datasource.url到底来自哪里。

3.2 把配置写到代码里,什么时候需要?

有些人喜欢用@ConfigurationProperties和@Value把配置读进代码,其实大多数情况下没必要。Spring Boot 的DataSourceProperties已经自动绑定了spring.datasource.*前缀。但下面几种场景我会主动写代码:

  • 动态数据源:根据业务上下文切换库(比如读写分离)。
  • 连接池类型不是 HikariCP,而是 Druid 或 Tomcat JDBC,需要额外自定义属性。
  • 多个数据源:一个 Spring Boot 应用同时连接两个或以上的数据库。

多数据源有一个容易踩的坑:如果你手工定义多个DataSourceBean,Spring Boot 的自动配置会失效,此时你必须自己指定@Primary。否则JdbcTemplate或TransactionManager注入的时候会报“No qualifying bean of type 'DataSource'”。

我这里给一个最简的多数据源示例代码思路,不展开全部代码:

@Bean @Primary @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); }

然后在使用的地方用@Qualifier指定具体数据源。

注意:多数据源不要同时搭配spring-boot-starter-data-jpa一起使用,除非你愿意处理两个EntityManagerFactory的复杂配置。如果只是做报表查询、跨库同步,用JdbcTemplate更稳。

4. 第三层面:MyBatis、JPA、JDBC 的配置差异,别混为一谈

4.1 MyBatis 特有配置:mapper 扫描、驼峰映射、日志输出

MyBatis 在 Spring Boot 里的配置除了数据源,还要关心 MyBatis 自身的参数:

mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • mapper-locations:XML 文件路径。如果你把 mapper 文件放在src/main/java下而没放在resources,记得改路径,否则启动报Invalid bound statement (not found)。
  • map-underscore-to-camel-case:数据库字段user_name映射到实体userName的关键。不加这个,你会发现查询结果全是 null,但 SQL 在数据库工具里跑明明有数据。
  • log-impl:控制台打印 SQL。不要在生产环境一直开着,性能损耗不大但日志量很大,建议只在 dev 环境开启。

我在实际项目中,遇到过“mapper 接口明明写了@Mapper注解,但还是报找不到 bean”的情况。原因是没加@MapperScan,或者加了但扫描包路径不对。两种解决办法二选一:

@SpringBootApplication @MapperScan("com.example.demo.mapper") public class DemoApplication { // ... }

或者在每个 mapper 接口上单独加@Mapper。我推荐用@MapperScan,一劳永逸。

4.2 JPA 的配置风格:自动建表、SQL 输出、命名策略

JPA 的配置和 MyBatis 很不一样。假如你用spring-boot-starter-data-jpa:

spring: jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect
  • ddl-auto:有none、validate、update、create、create-drop几个选项。开发阶段用update方便,但生产环境几乎不用create,否则每次启动都会删表重建,数据直接没了。
  • show-sql和format_sql:方便调试,生产环境记得关掉。
  • dialect:指定方言。Spring Boot 有时候会自动适配,但如果你连接的是 MySQL 8,而 Hibernate 还在用 MySQL5Dialect,可能导致语法生成错误。

避坑提示:JPA 和 MyBatis 不要同时加依赖。虽然技术上能共存,但两套持久层框架同时存在会让事务管理、实体映射变得非常混乱。一个项目尽量只选一种。

4.3 JDBC 原生方式:最直接但也要注意事务

如果你只引入了spring-boot-starter-jdbc,那配置相对简单,数据源配好之后可以直接注入JdbcTemplate:

@Autowired private JdbcTemplate jdbcTemplate; public List<Map<String, Object>> query() { return jdbcTemplate.queryForList("select * from user"); }

但要注意,JdbcTemplate本身不管理事务。你要在方法上写@Transactional,同时确保你的类被 Spring 容器管理。同事之前遇到过一个问题:在同一个类内部调用带@Transactional的方法,事务不生效——这是 Spring AOP 的经典坑,因为自调用不走代理对象。解决办法是拆到不同的类里调用,或者使用TransactionTemplate:

transactionTemplate.execute(status -> { jdbcTemplate.update("update user set name = ? where id = ?", "张三", 1); return null; });

TransactionTemplate的好处是摆脱了代理机制的坑,明确控制提交和回滚时机,个人认为在某些场景比@Transactional更好用。

5. 配置之后,如何验证你的连接真的没问题?

5.1 启动测试与actuator健康检查

配置写完,先别急着敲业务代码。把应用启动起来,观察日志里有没有Tomcat started on port(s): 8080,然后再做几个验证:

  • 加一个简单的 controller 或者用CommandLineRunner执行一次查询,确认能查到数据。
  • 引入spring-boot-starter-actuator,然后访问/actuator/health查看数据库状态。如果配置正确,健康检查结果里会包含db: { status: "UP" }。
  • 为了只看数据源,还可以访问/actuator/beans搜索dataSource相关 Bean,看是否只有一个 HikariDataSource,或者存在多个但你指定的@Primary是否正确。

我习惯在每个项目里都加 actuator 依赖,不只是为了健康检查,更重要的是配置错误时候能快速定位。

5.2 数据库工具预览与数据初始化

配置完数据库连接后,很多人会忽略一个细节:项目启动时要不要自动初始化表结构和初始数据。Spring Boot 提供spring.sql.init相关配置,比如:

spring: sql: init: mode: always schema-locations: classpath:sql/schema.sql >spring: datasource: password: ${DB_PASSWORD}
  • 使用 Jasypt 对密码加密,启动时解密。依赖com.github.ulisesbocchio:jasypt-spring-boot-starter,配置文件中写ENC(加密串)。
  • 对于多环境(dev/test/prod),用spring.profiles.active配合application-{profile}.yml隔离配置。
  • 如果公司有 Nacos、Apollo 这类配置中心,把spring.datasource.*挪到配置中心管理,可以动态刷新。不过连接池参数改了不一定热生效,还是得重启。

说到底,配置数据库不是背参数,而是要理解 Spring Boot 的自动配置机制、理解连接池的运行周期、理解连接字符串里每个参数的作用。很多看起来“玄学”的问题,最终都能落脚到一个具体的参数或依赖上。

8. 写在最后的个人体会

配置数据库这个事,我已经在 Spring Boot 项目里做过太多次,但每换一个新环境、新数据库版本、新依赖版本,都可能踩到新的坑。我的习惯是:本地先用数据库工具手动验证连接信息,再改项目的 yml;改动一次只改一个变量,方便定位问题;遇到报错先把完整堆栈读完再搜答案,而不是盲目复制网上的配置。

如果你刚接触 Spring Boot,我建议先不要追求复杂的花活,用最简配置跑通一个查询,然后再逐步加连接池参数、多数据源、配置中心这些进阶内容。另外,日常开发时把 MyBatis 的 SQL 日志打开,能省去非常多数据对不上的排查时间。这套思路帮我处理过很多“莫名奇妙”的数据库连接问题,希望你也能少踩几个坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询