
简介面向 Java 后端初学者与需要快速跑通数据库连接的开发者内容围绕 Spring Boot 整合 JDBC 访问 MySQL 的完整链路展开涉及依赖引入、连接参数配置、Controller 与实体类分层写法及建库建表脚本可对照复现一套可运行的示例工程也适合课程实验或小型项目脚手架使用。压缩包共 136 个文件、约 637MB3 个 java 源文件与 5 个 class 对应核心示例代码3 个 sql 脚本提供建表与初始化数据properties、xml 等文件说明连接与工程结构另有 92 个 dll、4 个 exe 以及 zip、msi 安装包便于在 Windows 下一次性备齐 JDK、数据库与驱动。目前已有 601 人学习下载源码、SQL 脚本与安装包相互配合可省去逐个查找驱动、核对版本的时间把重点放在连接串、数据源参数与增删改查实现上遇到驱动缺失或连接失败也有现成环境可对照排查。1. 版本先对齐JDK 17、Spring Boot 3.2 与 MySQL 8.0 的组合上周被人拉去看一个跑不起来的工程pom 里 Spring Boot 写的是 3.2机器上 JAVA_HOME 还指着 JDK 8MySQL 装的是 5.7。把 JDK 换掉之后连接串里的驱动类又还写着com.mysql.jdbc.Driver问题一层一层往外冒。用 Java 通过 JDBC 连 MySQL 这件事本身不复杂复杂的是 Spring Boot 版本、JDK 版本、MySQL 版本、驱动坐标这四样必须互相匹配只要有一个错位报错信息就会指向别的地方。这套环境几乎是每个 Java 后端都要接触的第一条数据库链路读写、连接池、字符集、时区全都压在它上面。装对了十分钟能跑通装不对能折腾一整天。下面按我实际的顺序来先把 JDK 和 Maven 配干净再把 MySQL 8.0 初始化好并开出最小权限账号然后回到工程里配连接串和 HikariCP最后用三层自检确认它真的能读写。2. 装 JDK 与 Maven从 JAVA_HOME 到镜像源一次配干净本章做的事情只有两件让命令行认出唯一的那个 JDK让 Maven 能稳定地把依赖拉下来。听起来像废话但后面百分之六十的诡异报错根都在这两步。2.1 JDK 版本怎么选装完怎么验Spring Boot 3.x 的最低要求是 JDK 17Spring Boot 2.7 那一代还能在 JDK 8 上跑。选哪个不是喜好问题是匹配问题Spring Boot最低 JDKJDBC 驱动坐标命名空间2.7.xJDK 8mysql:mysql-connector-javajavax.*3.0.x - 3.2.xJDK 17com.mysql:mysql-connector-jjakarta.*3.3.x 及以上JDK 17com.mysql:mysql-connector-jjakarta.*我一般直接下 Temurin 或 Zulu 的 JDK 17 免安装压缩包解到一个不带空格、不带中文的目录比如D:\env\jdk17或/opt/jdk17。带空格的路径在某些脚本里会被拆成两个参数这类坑排查起来非常不直观。# 解压后先看目录结构确认 bin 目录直接在解压目录下 ls /opt/jdk17 # 期望看到 bin conf include jmods legal lib release 这一层解压出来如果多套了一层jdk-17.0.x目录JAVA_HOME 就要指到那一层指错一层是最常见的翻车点。确认结构没问题再设环境变量。# Linux / macOS写进 ~/.bashrc 或 ~/.zshrc export JAVA_HOME/opt/jdk17 export PATH$JAVA_HOME/bin:$PATHREM Windows系统环境变量里配不要只在当前终端 set setx JAVA_HOME D:\env\jdk17 setx PATH %JAVA_HOME%\bin;%PATH%JAVA_HOME指的是 JDK 根目录不带\binPATH里加的才是%JAVA_HOME%\bin。这两个混着写命令行能跑java但 Maven 和 IDE 会各自报不同的错属于典型的玄学现场。配完一定要新开一个终端验证java -version # 应输出 17.x javac -version # 应输出 17.x和上面一致 echo $JAVA_HOME # Windows 用 echo %JAVA_HOME%java -version和javac -version版本不一致说明 PATH 里排在前面的还有另一个 JDK把它挪走或者删掉。这一步不要偷懒跳过后面所有问题都建立在这个前提上。2.2 Maven 安装与 settings.xml 配置Maven 用 3.9.x 这一代就够了它自带的依赖解析对 Spring Boot 3 的 BOM 支持没问题。解压到D:\env\maven或/opt/maven同样把MAVEN_HOME和%MAVEN_HOME%\bin写进环境变量。真正要改的是conf/settings.xml重点三处本地仓库位置、镜像源、JDK 编译配置。settings xmlnshttp://maven.apache.org/SETTINGS/1.0.0 !-- 本地仓库挪出 C 盘/系统盘几百兆依赖堆在用户目录里迟早出事 -- localRepositoryD:/env/maven-repo/localRepository mirrors mirror idaliyun-central/id mirrorOfcentral/mirrorOf namecentral mirror/name urlhttps://maven.aliyun.com/repository/central/url /mirror /mirrors profiles profile idjdk17/id activation activeByDefaulttrue/activeByDefault jdk17/jdk /activation properties maven.compiler.source17/maven.compiler.source maven.compiler.target17/maven.compiler.target maven.compiler.release17/maven.compiler.release /properties /profile /profiles /settingslocalRepository里的路径用正斜杠Windows 下也建议用/反斜杠在 XML 里会被当转义符处理。mirrorOf写central只拦中央仓库如果写*会把所有仓库都拦下来某些公司私服就会被一起劫持表现是依赖莫名其妙 404。maven.compiler.release比source/target更严格它会让编译器对着 JDK 17 的 API 表校验避免你在 JDK 17 上用了 JDK 21 才有的方法却编译通过。配完验证mvn -v # 输出里要盯两行Maven 3.9.x 和 Java version: 17.xmvn -v里那行 Java version 是很多人忽略的黑匣子。它和java -version不一致说明 Maven 找到了另一个 JDK比如 IDE 内置的此时mvn clean package的编译结果和 IDE 里的编译结果会不一样症状是「IDE 能跑打包就报错」。2.3 三个最容易写错的路径第一条JAVA_HOME带上了\bin。症状是mvn -v报JAVA_HOME is set to an invalid directory。第二条PATH里同时存在新旧两个 JDK 的 bin且顺序不对。症状是java -version是 17javac -version是 8或者反过来。解决办法不是反复改而是把不用的那个 JDK 从 PATH 里彻底删掉多版本共存靠脚本切换别指望 PATH 顺序。第三条改完环境变量没有重启终端或者 IDE 是从旧终端拉起来的。Windows 上尤其明显setx只对之后新开的进程生效。我习惯的做法是改完环境变量后直接关掉所有终端和 IDE重新开一个再验证一遍java -version、mvn -v、IDE 里的 Project SDK 三处指向同一个 JDK 17。3. 装 MySQL 8.0初始化、建库与最小权限账号MySQL 8.0 和 5.7 之间有几处会直接影响 JDBC 连接的变化默认认证插件改成了caching_sha2_password默认字符集改成了utf8mb4utf8这个词的语义也被收紧了。用 5.7 时代的经验去装 8.0大概率会在连接阶段卡住。3.1 免安装包初始化与注册服务Windows 上我一般用 ZIP 包可控性最强。解压到D:\env\mysql-8.0.36在同级建一个my.ini[mysqld] port3306 basedirD:/env/mysql-8.0.36 datadirD:/env/mysql-8.0.36/data character-set-serverutf8mb4 collation-serverutf8mb4_0900_ai_ci default-time-zone08:00 max_connections200 # 8.0 用这个参数8.4 起换成了 authentication_policy default-authentication-pluginmysql_native_password [client] default-character-setutf8mb4datadir必须指向一个空目录或者不存在的目录初始化时 MySQL 会往里写系统表。目录里有残留文件--initialize会直接失败。default-time-zone设成固定偏移量而不是时区名是为了避免服务器本身没装时区表时启动报错。default-authentication-plugin这一行在 8.0 上还认8.4 之后会被废弃如果你的小版本是 8.4把它换成authentication_policymysql_native_password。初始化并注册服务# 用 --console 把初始化日志打到屏幕上不要让它进 error log 里找不着 mysqld --defaults-fileD:/env/mysql-8.0.36/my.ini --initialize-insecure --console # 注册为系统服务服务名自己起别和已有的 MySQL 冲突 mysqld --install MySQL80 --defaults-fileD:/env/mysql-8.0.36/my.ini # 启动 net start MySQL80--initialize-insecure生成的是空密码的 root好处是能在本地直接登进去改坏处是这中间有一段时间数据库是完全敞开的。我的习惯是初始化完立刻登录改密码中间不接入任何网络。ALTER USER rootlocalhost IDENTIFIED BY 换成你自己的强密码; FLUSH PRIVILEGES;Linux 上如果用 tar.gz 包流程一样只是要多建一个mysql系统用户并把datadir的属主改过去否则--initialize会因为权限不足中途退出。启动失败时先看datadir下的.err文件里面会写清楚是端口占用、权限问题还是配置项不认识。3.2 建库建表字符集和排序规则一次定死字符集这件事没有后悔药表建完再改要重建数据。8.0 的默认已经是utf8mb4但我还是习惯显式写出来因为配置文件被覆盖、或者从别处导入的 SQL 脚本里写着utf8最后都会落回三字节的utf8mb3存 emoji 或者部分生僻字就报Incorrect string value。CREATE DATABASE IF NOT EXISTS demo_db DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_0900_ai_ci; USE demo_db; CREATE TABLE t_order ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键, order_no VARCHAR(32) NOT NULL COMMENT 订单号, amount DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT 金额, remark VARCHAR(255) DEFAULT NULL COMMENT 备注, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_amount (amount) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;几个取舍说一下。金额用DECIMAL不用DOUBLE浮点在累加时会有尾差对账时对不上是非常难受的事。order_no上建唯一索引业务层的幂等就多一道保险插入重复单号会直接抛异常而不是静默写脏数据。created_at用DATETIME配DEFAULT CURRENT_TIMESTAMP比TIMESTAMP少一层 2038 年的隐患代价是不带时区信息应用侧要保证写入的时间是同一个时区。utf8mb4_0900_ai_ci里的ai是重音不敏感、ci是大小写不敏感。要做严格区分大小写的用户名之类的字段单列指定utf8mb4_0900_as_cs别为了一个字段把整库的排序规则改掉。3.3 应用账号不给 root也不给 DDL应用连接数据库用的账号和你运维用的账号必须是两个。应用账号只给 DML 权限建表、改表这类操作走单独的迁移流程。-- 应用账号host 用 % 还是 localhost 取决于应用和库是否同机 CREATE USER app_demo% IDENTIFIED BY App_Str0ng_Pwd; -- 只给增删改查不给 DROP/ALTER/CREATE GRANT SELECT, INSERT, UPDATE, DELETE ON demo_db.* TO app_demo%; FLUSH PRIVILEGES;app_demo%和app_demolocalhost在 MySQL 里是两个不同的账号只建了%的账号从本机连不一定能登进去反过来也一样。本地开发时两个都建或者明确用127.0.0.1走 TCP 而不是 socket。另外 8.0 默认的caching_sha2_password在 JDBC 侧需要额外参数配合如果你暂时不想纠结可以把账号指定成mysql_native_passwordCREATE USER app_demo% IDENTIFIED WITH mysql_native_password BY App_Str0ng_Pwd;但更推荐的做法是保留默认插件在连接串里加allowPublicKeyRetrievaltrue这一点下一章会展开。4. 工程接 JDBCpom 坐标、连接串参数与 HikariCP 调参到这一步环境已经就绪剩下的全在工程里。Spring Boot 用spring-boot-starter-jdbc这一套没有 ORM纯JdbcTemplate好处是 SQL 可控、启动快、排查时链路短。4.1 依赖坐标两个 starter 加一个驱动parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent properties java.version17/java.version /properties dependencies !-- 带 HikariCP 和 JdbcTemplate 的自动配置 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency !-- 8.0.31 之后坐标从 mysql:mysql-connector-java 改成 com.mysql:mysql-connector-j -- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency /dependencies驱动这块不要自己写version。spring-boot-starter-parent的依赖管理里已经锁好了和当前 Boot 版本匹配的驱动版本手写版本号会破坏这层对应关系常见后果是驱动版本过高导致Unsupported class file major version或者过低不认 8.0 的认证插件。com.mysql:mysql-connector-j这个坐标是 8.0.31 之后才有的。老教程里的mysql:mysql-connector-java在 Boot 3 的 BOM 里已经不再管理写了也不报错但版本会变成你自己指定的那个属于埋雷。4.2 连接串逐项拆解spring: datasource: url: jdbc:mysql://127.0.0.1:3306/demo_db?useUnicodetruecharacterEncodingutf8useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneGMT%2B8rewriteBatchedStatementstrueconnectTimeout3000socketTimeout60000 username: app_demo password: App_Str0ng_Pwd driver-class-name: com.mysql.cj.jdbc.Driver hikari: pool-name: demo-pool maximum-pool-size: 10 minimum-idle: 2 connection-timeout: 3000 idle-timeout: 600000 max-lifetime: 1740000 connection-init-sql: SET NAMES utf8mb4逐项说清楚改的时候心里有数参数作用取值建议useUnicodecharacterEncoding客户端与服务端的字符编码协商固定trueutf8对应服务端 utf8mb4useSSL是否走 SSL 握手内网自建库false云上实例按服务商要求开allowPublicKeyRetrieval允许客户端向服务端索取公钥配合caching_sha2_password且不开 SSL 时必须有serverTimezone驱动解析时间用的时区写固定偏移GMT%2B8必须编码成%2BrewriteBatchedStatements把批量 insert 改写成多值语句批量写入场景必须开否则批处理是逐条发connectTimeout建连超时毫秒3000 足够别用默认值等半天socketTimeout单次读超时毫秒60000长事务场景按最慢 SQL 调driver-class-name在 Boot 3 8.x 驱动下其实可以省略驱动会自动从 URL 推断。但省略之后如果哪天换成了连接池里的多数据源排查时少一个抓手所以我一般还是显式写上而且一定写com.mysql.cj.jdbc.Driver不是老版的com.mysql.jdbc.Driver。connection-init-sql设SET NAMES utf8mb4是双保险防止服务端character_set_client被别处改掉。如果服务端配置已经对了这条语句是幂等的不产生额外开销。4.3 HikariCP 参数max-lifetime 必须小于 wait_timeoutSpring Boot 默认用的连接池就是 HikariCP不引额外依赖。参数里最容易出事的是max-lifetime。MySQL 服务端有个wait_timeout默认 28800 秒8 小时空闲连接超过这个时间会被服务端单方面踢掉。而连接池并不知道对面已经断了仍然把这条连接当可用连接发出去症状是「应用闲置一夜之后第一批请求全部报Communications link failure」。解决办法就是让连接池主动先于服务端回收hikari: max-lifetime: 1740000 # 29 分钟必须小于 MySQL wait_timeout idle-timeout: 600000 # 10 分钟空闲多久后允许被回收 keepalive-time: 300000 # 5 分钟定期探活防止被中间网络设备静默断连max-lifetime要比wait_timeout小留出至少几分钟的余量。反过来max-lifetime设得过小比如 30 秒会让连接频繁重建建连本身就是一次 TCP 加认证握手高并发下这笔开销很可观。maximum-pool-size不要拍脑袋设大。池子大小的瓶颈通常不在数据库连接数而在后端能扛住的并发 SQL 数量。10 到 20 是大部分中小业务合适的区间配上connection-timeout: 3000拿不到连接就快速失败比无限等待更容易定位问题。4.4 JdbcTemplate 的读写写法配置好了不代表会用。JdbcTemplate的坑集中在参数传递和行映射上Repository public class OrderDao { private final JdbcTemplate jdbcTemplate; public OrderDao(JdbcTemplate jdbcTemplate) { this.jdbcTemplate jdbcTemplate; } // 写入占位符按顺序传参返回影响行数 public int insert(String orderNo, BigDecimal amount, String remark) { String sql INSERT INTO t_order(order_no, amount, remark) VALUES (?, ?, ?); return jdbcTemplate.update(sql, orderNo, amount, remark); } // 查询RowMapper 放中间参数跟在后面别把顺序写反 public ListOrder findTop50(BigDecimal minAmount) { String sql SELECT id, order_no, amount, remark, created_at FROM t_order WHERE amount ? ORDER BY id DESC LIMIT 50; return jdbcTemplate.query(sql, (rs, rowNum) - { Order o new Order(); o.setId(rs.getLong(id)); o.setOrderNo(rs.getString(order_no)); o.setAmount(rs.getBigDecimal(amount)); o.setRemark(rs.getString(remark)); o.setCreatedAt(rs.getTimestamp(created_at).toLocalDateTime()); return o; }, minAmount); } // 批量写必须配合 rewriteBatchedStatementstrue 才能合成多值语句 public int[] batchInsert(ListOrder orders) { String sql INSERT INTO t_order(order_no, amount, remark) VALUES (?, ?, ?); return jdbcTemplate.batchUpdate(sql, orders, 500, (ps, o) - { ps.setString(1, o.getOrderNo()); ps.setBigDecimal(2, o.getAmount()); ps.setString(3, o.getRemark()); }); } }update和query的参数顺序不一样update(sql, args...)参数直接跟在 SQL 后面query(sql, rowMapper, args...)中间夹了一个RowMapper。写反了不会编译报错都是 Object运行时报参数个数不匹配这类错误看着很莫名其妙。batchUpdate(sql, collection, batchSize, setter)里的batchSize是每多少条刷一次500 是个比较稳的值。批处理真正的性能开关在连接串的rewriteBatchedStatementstrue上不开这个参数驱动会老老实实一条一条发看着用了批量接口实际毫无收益。5. 排查手册连不上、连上查不出、查出来乱码的五种翻车连接类的报错有个共同点错误信息本身往往不指向真正的原因。下面五条是我踩过并且反复在别人机器上见到的按「现象 → 原因 → 解决」记下来。5.1 Communications link failure现象应用启动时报com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure堆栈里没有更具体的信息。原因TCP 层就没连上可能是服务没起、端口不对、防火墙拦了也可能是 URL 里的主机名解析到了别处。还有一种隐蔽情况是服务端bind-address只监听127.0.0.1从别的机器连必然失败。解决先绕开 Java 验证网络层用命令行客户端直连同一个地址端口。# 先看端口通不通 telnet 127.0.0.1 3306 # 再用客户端登一次确认账号密码和库名都没问题 mysql -h 127.0.0.1 -P 3306 -u app_demo -p demo_db客户端能连、Java 连不上问题就在 URL 或驱动两边都连不上去查服务和防火墙。不要一上来就改代码。5.2 Access denied for user app_demolocalhost现象Access denied for user app_demolocalhost (using password: YES)但客户端用同样的账号密码能登进去。原因报错里的 host 部分是 MySQL 对来源的判定结果不是你写在 URL 里的那个。用localhost连会走 socketMySQL 认为来源是localhost用127.0.0.1连走 TCP认为来源是127.0.0.1。只建了app_demo%的账号本机 socket 连接就可能匹配不上。解决查一下实际有哪些账号再按需补齐。SELECT user, host, plugin FROM mysql.user WHERE user app_demo;缺哪个 host 补哪个本地开发把localhost和%都建上最省事。5.3 Public Key Retrieval is not allowed现象java.sql.SQLException: Public Key Retrieval is not allowed。原因MySQL 8.0 默认认证插件是caching_sha2_password在不开 SSL 的连接上客户端需要向服务端索取 RSA 公钥来加密密码驱动默认禁止这个行为。解决连接串加allowPublicKeyRetrievaltrue。这相当于信任服务端返回的公钥所以只在内网或者已经确认链路安全的环境里开公网实例应该走 SSL 而不是开这个开关。5.4 中文乱码与 Incorrect string value现象写入中文报Incorrect string value: \xE4\xBD\xA0... for column remark或者读出来是一串问号。原因表或列的字符集是utf8mb3三字节存不下四字节字符或者连接串没声明编码服务端按默认的latin1处理。解决三层一起查缺一层都不行。-- 库、表、列三层的字符集都要是 utf8mb4 SELECT DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME demo_db; SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA demo_db; SHOW FULL COLUMNS FROM t_order;发现某一层是utf8用ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4改掉同时确认连接串带了characterEncodingutf8。改表的时候注意CONVERT TO会重建表大表要挑低峰期做。5.5 Connection is not available, request timed out现象跑一段时间后开始报HikariPool-1 - Connection is not available, request timed out after 3000ms重启应用就恢复。原因连接泄漏。某段代码通过DataSource.getConnection()手动拿了连接却没关池子里的连接被一点点耗光。用JdbcTemplate一般不会有这问题但混合了手写 JDBC 的代码就难说。解决把池子的运行状态暴露出来看不要凭猜。# 打开 Hikari 的指标和 Actuator 的数据库健康检查 management: endpoints: web: exposure: include: health,metrics health: db: enabled: true访问/actuator/metrics/hikaricp.connections.active和hikaricp.connections.pending如果 active 长期顶在maximum-pool-size而 pending 一直在涨基本可以确认是泄漏。再把手动拿连接的地方全部改成 try-with-resources或者统一收口到JdbcTemplate。短期止血的办法是把leak-detection-threshold设成 20000毫秒超过 20 秒没归还的连接会在日志里打出堆栈直接指出是哪一行代码拿的。6. 验证跑通三层自检把「能启动」变成「能读写」应用能启动不代表链路通了。Spring Boot 启动时默认是懒加载数据源的很多时候「启动成功」只是意味着配置解析没报错真正建连要等到第一次请求。我一般按三层往下验。第一层网络与账号。用命令行客户端从应用所在的机器直连一次确认主机、端口、账号、库名四个信息全部正确。这一层不过后面所有验证都是白费。第二层数据源。在启动类旁边加一个ApplicationRunner让它在容器就绪后立刻拿一条连接出来把元数据打印出来Component public class DataSourceSelfCheck implements ApplicationRunner { private final DataSource dataSource; public DataSourceSelfCheck(DataSource dataSource) { this.dataSource dataSource; } Override public void run(ApplicationArguments args) throws Exception { try (Connection conn dataSource.getConnection()) { DatabaseMetaData meta conn.getMetaData(); // 三行输出能同时证明连接可用、驱动版本正确、服务端版本符合预期 System.out.println(url meta.getURL()); System.out.println(driver meta.getDriverName() meta.getDriverVersion()); System.out.println(product meta.getDatabaseProductVersion()); System.out.println(readOnly conn.isReadOnly()); } } }这段代码的价值在于把问题暴露在启动阶段。meta.getURL()会回显实际生效的连接串能立刻看出时区、SSL 这些参数有没有被覆盖getDriverVersion()和getDatabaseProductVersion()对上你预期的版本就排除了驱动错配。用 try-with-resources 包住验证完连接立刻归还不占用池子。第三层业务读写。跑一个最小的闭环插入一条、按条件查出来、更新一次、再删掉。用测试类做最方便SpringBootTest起完整容器断言影响行数和查询结果。这一步能抓到字符集、字段类型映射、事务边界的问题比如DECIMAL映射成double造成的精度丢失只有真的写进去再读出来才会暴露。三层都过之后再补一个日常习惯把/actuator/health挂到监控上db那一项是 DOWN 就告警。它比任何日志都直接因为它每隔一段时间真的去拿一次连接。血泪经验是我以前图快装完直接mvn spring-boot:run看到 Started 就宣布搞定结果第二天同事拉代码在他机器上因为max-lifetime没配、连接串时区写成了UTC批量插入的时间全部偏了八小时查了半天以为是业务逻辑问题。从那以后我每次配完这套环境都会强制走一遍上面三层验证尤其是第二层那段元数据打印跑一次只要几秒钟省下的排查时间是以小时计的。整套的 pom、yml、建表脚本和自检代码我打在一个包里了照着自己的路径改改就能复现。希望帮到你。本文还有配套的精品资源点击获取