ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot数据库配置全解析:从单数据源到连接池与多数据源

Spring Boot数据库配置全解析:从单数据源到连接池与多数据源 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 groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/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.DriverMySQL 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?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456这里面有几个参数容易被忽略但特别重要driver-class-name驱动类名必须和依赖里的驱动版本对应。url里的useSSLfalse本地开发时建议关掉 SSL否则 MySQL 8 默认开启 SSL 会导致连接警告或失败。serverTimezoneAsia/Shanghai不设置这个你可能会遇到“数据库连接失败The server time zone value Öйú±ê׼ʱ¼ä is unrecognized”这种乱码报错。allowPublicKeyRetrievaltrue如果 MySQL 8 使用caching_sha2_password认证插件连接工具或驱动可能需要这个参数否则可能报Public Key Retrieval is not allowed。我建议把allowPublicKeyRetrievaltrue这个参数加上尤其在用 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}.ymlapplication.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 应用同时连接两个或以上的数据库。多数据源有一个容易踩的坑如果你手工定义多个DataSourceBeanSpring 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.StdOutImplmapper-locationsXML 文件路径。如果你把 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-jpaspring: jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQL8Dialectddl-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那配置相对简单数据源配好之后可以直接注入JdbcTemplateAutowired private JdbcTemplate jdbcTemplate; public ListMapString, Object query() { return jdbcTemplate.queryForList(select * from user); }但要注意JdbcTemplate本身不管理事务。你要在方法上写Transactional同时确保你的类被 Spring 容器管理。同事之前遇到过一个问题在同一个类内部调用带Transactional的方法事务不生效——这是 Spring AOP 的经典坑因为自调用不走代理对象。解决办法是拆到不同的类里调用或者使用TransactionTemplatetransactionTemplate.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 日志打开能省去非常多数据对不上的排查时间。这套思路帮我处理过很多“莫名奇妙”的数据库连接问题希望你也能少踩几个坑。
返回列表