☰
SpringBoot集成JDBC连接MySQL:配置、避坑与连接池改造指南
2026/10/11 5:17:37 网站建设 项目流程

简介:一套面向Java SpringBoot开发者的MySQL JDBC连接完整解决方案,适合初学数据访问层或需快速搭建数据库接入模块的读者,既能用于课程设计,也能作为企业项目初始化脚手架参考。资源共136个文件,压缩包约637MB,内含可直接运行的Java源码、SQL建表脚本、XML与properties配置,并打包了92个DLL及多种EXE、MSI安装组件,免去另行寻找对应驱动版本和安装依赖的麻烦。内容覆盖JDBC驱动加载、连接配置、SQL执行与结果集处理等完整流程,源码中可以看到Controller接口、实体类以及JDBC连接封装代码,结构层次清晰。已有598人学习浏览,针对常见连接异常、时区与SSL等问题,资源内附有排错思路,帮助开发者快速定位问题。拿到手后不用再拼凑零散教程,即可对照理解SpringBoot整合JDBC的经典写法,无论作为学习样例还是生产环境快速接入MySQL的参考,实用性都较强。

1. 一个 JDBC 入门工程,卡住你的往往不是代码

做 Java 后端的人几乎都绕不过这一步:SpringBoot 工程要连 MySQL,但 JDBC 这层看似简单,实际配置起来却有一堆隐藏门槛。驱动版本不匹配、时区报错、SSL 警告、连接池参数看不懂——这些不是代码问题,而是“经验问题”。这套《Java SpringBoot 使用JDBC连接Mysql数据库》解决方案,把源码、安装包、建表脚本整整齐齐打成一个包。对于刚学 SpringBoot 的初学者、做课程设计的学生、以及想快速搭一个 JDBC 最小工程的老手,它都是一份能直接抄作业的参考。我拆过不少类似资源,这套的完整度属于中上。下面把它的工程结构、配置要点和踩坑记录完整过一遍。

2. SpringBoot + JDBC 的选型逻辑:为什么不直接用 MyBatis

2.1 JDBC 在 SpringBoot 技术栈里的定位

SpringBoot 整合数据访问层,市面上最常见的是 MyBatis、Spring Data JPA,而 JDBC 属于“最底层的那一层”。很多人觉得 JDBC 太原始,写 SQL 要自己拼字符串、处理 ResultSet,麻烦还不安全。但在两个场景里,JDBC 反而是更合适的选择:

  • 学习期:先搞清楚驱动加载、Connection 创建、Statement 执行、ResultSet 遍历这几个最原始的步骤,再上框架时才能理解框架帮你做了什么。
  • 轻量项目:一个内部工具、一个实验 Demo,表结构就两三张,引入 MyBatis 反而要配 mapper 文件、XML、插件,属于杀鸡用牛刀。

这套资源用的就是最朴素的思路:SpringBoot 管依赖注入和事务,JDBC 管数据库操作,没有中间层。工程里没有 mapper XML,没有 DAO 自动生成,Controller 直接调 JDBC 工具类。这种做法对理解“SpringBoot 如何管理非 Spring 管理的对象”特别有帮助——因为 JDBC 的 Connection 不是 Spring 的 Bean,你需要手动管理它的生命周期。

2.2 驱动版本与数据库版本的对应关系

拆开这份资源的 pom.xml,会发现驱动依赖是 mysql-connector-java。这个坐标有两个版本体系要注意:5.1.x 系列对应 MySQL 5.x,而针对 MySQL 8.0 以上要用 mysql-connector-java 8.0.x 或直接换新坐标 com.mysql:mysql-connector-j。资源包里如果配套安装的是 MySQL 5.7,驱动用 5.1.47 这类老版本完全没问题;如果自己电脑上装的是 MySQL 8.0,却用了驱动 5.1 系列,启动后会报:

com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized

这个报错信息里的乱码是编码显示问题,核心是驱动 5.1 不认识 MySQL 8.0 的时区配置。解决方式有两种:要么升级驱动,要么在 JDBC URL 里加 serverTimezone=Asia/Shanghai。资源包里如果带安装包,大概率是 5.7 版本,但接手这份工程时建议先看一下驱动版本,再决定要不要把引入的 jar 包版本对齐。

2.3 SpringBoot 与 JDBC 的“连接管理”差异

SpringBoot 默认不会帮你管理 JDBC 连接。用了 JdbcTemplate 才会走 HikariCP 连接池,但直接用 java.sql.DriverManager 的话,每次 getConnection 都是新建连接,用完必须 close。这套资源属于“半自动”方案:自己写了一个 DBUtil,里面做连接的创建和关闭。你一定会在代码里看到类似下面的工具类:

public class DBUtil { private static String url = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai"; private static String user = "root"; private static String password = "123456"; static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }

这段代码里的 Class.forName 在 JDBC 4.0 之后其实可以省略,因为驱动 jar 包里有 SPI 自动注册机制。但保留它有两个原因:一是某些旧版本 MySQL 驱动仍需手动注册,二是写上后代码语义更明确,初学者能看懂“驱动加载”这一步到底做了什么。url 参数里的 useSSL=false 是为了避免本地开发时 SSL 握手警告,serverTimezone 是为了解决时区报错,这两个参数在 5.1 驱动下可以不加,但 8.0 驱动下缺一个就会启动失败。

2.4 参数表:JDBC URL 核心参数配置

拿到资源后第一件事,不是跑通,而是看懂配置。JDBC URL 里的每个参数都有实际影响,这张表建议存下来:

参数名示例值作用不设置时的后果
serverTimezoneAsia/Shanghai指定服务器时区MySQL 8.0 下直接连接失败
useSSLfalse关闭 SSL 加密显示警告但一般能连上
characterEncodingutf8指定字符编码中文乱码,写入数据变问号
allowPublicKeyRetrievaltrue允许获取公钥MySQL 8.0 下密码认证失败
rewriteBatchedStatementstrue重写批量 SQL批量插入性能极差
useUnicodetrue启用 Unicode配合 characterEncoding 使用

allowPublicKeyRetrieval 这个参数是 MySQL 8.0 的典型坑。MySQL 8.0 默认使用 caching_sha2_password 认证插件,当客户端第一次连接时,服务器会发送公钥,客户端需要设置 allowPublicKeyRetrieval=true 才能获取。很多资源包的配置文件里没写这个参数,导致数据库连不上、报错信息指向密码错误,折腾一圈发现是参数缺失。这套资源如果自己新建工程时照搬会踩这个坑,如果你用的 MySQL 是 5.7,则可以不必关心它。

3. 把资源包跑起来:从安装 MySQL 到跑通第一条 SQL

3.1 先看包里的目录结构

解压这份资源后,目录大概长这样(不同来源的资源包结构会略有差异,但核心内容一致):

springboot-jdbc-mysql/ ├── sql/ │ └── init.sql ├── src/ │ ├── main/ │ │ ├── java/com/example/demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/UserController.java │ │ │ ├── dao/UserDao.java │ │ │ └── util/DBUtil.java │ │ └── resources/ │ │ └── application.properties ├── pom.xml ├── mysql-installer/ │ └── mysql-installer-community-8.0.x.msi └── 使用说明.md

我的建议是:先把 使用说明.md 读完,再看 sql/init.sql,最后打开 pom.xml。很多同学一上来就点开 src 里的代码,结果数据库还没建、表也没建,跑起来全是报错,然后认为是资源的问题。这套包里的 sql 目录一般放着建库建表脚本,内容类似:

CREATE DATABASE IF NOT EXISTS springboot_jdbc_demo DEFAULT CHARACTER SET utf8mb4; USE springboot_jdbc_demo; CREATE TABLE IF NOT EXISTS t_user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, password VARCHAR(100) NOT NULL, email VARCHAR(100), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO t_user (username, password, email) VALUES ('admin', '123456', 'admin@example.com'), ('test', '123456', 'test@example.com');

建表脚本里用了 utf8mb4 字符集,这一点很重要。MySQL 的 utf8 实际只支持最多 3 字节的字符,而表情符号等 4 字节字符存储会报错,utf8mb4 才是完整的 UTF-8 实现。如果你把脚本改成 utf8,后面写入 emoji 或特殊符号时会出现 Incorrect string value 错误,这是个高频坑。

执行脚本时,建议用命令行或图形化工具(如 Navicat)把 init.sql 整体跑一遍,不要只建库不建表。里面的测试数据是给后面的 Controller 接口用的,如果没有这些数据,查询接口会返回空数组,容易误判成工程代码有问题。

3.2 SpringBoot 工程配置:application.properties 是关键

资源包里 application.properties 的内容大概是:

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

注意这里用的是 spring.datasource.* 前缀,但在纯 JDBC 直连方案里,SpringBoot 并不会自动读取这些配置生成 DataSource,除非你用了 spring-boot-starter-jdbc。如果资源里只引入了 mysql-connector-java 而没有引入 jdbc starter,那么这些配置只是“摆设”——真正生效的是 DBUtil 类里硬编码的那几个值。我拆过几套类似的资源,DBUtil 里的账号密码和 application.properties 不一致的情况时有发生,建议先检查 DBUtil 里的写死值,以它为准。

如果你决定统一配置,可以把 DBUtil 改造成从 application.properties 读取:

@Configuration public class DBConfig { @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } }

但这里有个大坑需要注意:Connection 不能直接作为单例 Bean 注册。JDBC Connection 是有状态的、线程不安全的,如果直接把它放进 Spring 容器管理,多个请求共用一个连接会导致事务混乱、连接关闭后无法复用等问题。正确的做法是把 DataSource 注册成 Bean,每次从 DataSource 获取新连接:

@Bean public DataSource dataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl(url); config.setUsername(username); config.setPassword(password); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); return new HikariDataSource(config); }

资源包里如果用的是直连方案,建议你按这个方式做一次升级改造——把 DriverManager 替换成连接池管理,后面上生产环境时差异会非常明显。

3.3 Controller 与 DAO 的调用链路

资源包里的 Controller 代码不算复杂,典型的 JDBC 访问方式,大概长这样:

@RestController @RequestMapping("/user") public class UserController { @Autowired private UserDao userDao; @GetMapping("/list") public List<Map<String, Object>> list() { return userDao.findAll(); } @GetMapping("/{id}") public Map<String, Object> detail(@PathVariable Integer id) { return userDao.findById(id); } @PostMapping("/add") public String add(@RequestBody User user) { boolean flag = userDao.insert(user.getUsername(), user.getPassword(), user.getEmail()); return flag ? "success" : "fail"; } }

UserDao 内部用 JDBC 执行 SQL。这里的实现方式决定了这套资源的“学习价值”——如果你之前只写过 MyBatis,看看这个 DAO 层的写法会让你想明白很多底层问题:

@Repository public class UserDao { public List<Map<String, Object>> findAll() { String sql = "SELECT id, username, email, create_time FROM t_user"; List<Map<String, Object>> list = new ArrayList<>(); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); ps = conn.prepareStatement(sql); rs = ps.executeQuery(); while (rs.next()) { Map<String, Object> map = new HashMap<>(); map.put("id", rs.getInt("id")); map.put("username", rs.getString("username")); map.put("email", rs.getString("email")); map.put("createTime", rs.getTimestamp("create_time")); list.add(map); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(conn, ps, rs); } return list; } }

注意这段代码里的两个细节。第一,PreparedStatement 用 ? 占位符,而不是直接拼接 SQL 字符串,这是防 SQL 注入的基础,资源包如果用了 Statement 拼 SQL 建议改成这种方式。第二,资源关闭放在了 finally 里,确保异常时也能执行 close,避免连接泄漏。这两个习惯比任何框架技巧都重要——面试官看代码,第一眼看的就是资源释放和 SQL 注入防范。

3.4 启动验证的完整流程

把代码跑起来的完整流程,按顺序执行:

第一步,确认 MySQL 服务已经启动。Windows 下检查服务列表里的 MySQL 服务状态,Linux/Mac 下用systemctl status mysql或service mysql status查看。

第二步,执行 sql/init.sql 建库建表。执行成功后,MySQL 对应库会看到 t_user 表并有三条测试数据。

第三步,启动 SpringBoot 工程。如果没有报错,控制台日志里会出现 Tomcat started on port(s): 8080 字样。

第四步,验证接口。浏览器直接访问http://localhost:8080/user/list,能看到 JSON 数组返回。

第四步里有个常见问题:如果密码里包含&、?这类特殊字符,写在 JDBC URL 里就会被解析成参数分隔符,导致连接失败。比如密码是 abc&123,URL 里写 jdbc:mysql://localhost:3306/db?password 就会把 & 后面的部分当成新参数,需要做 URL 编码。这个坑容易让人误判成密码错误,实则是特殊字符引起的解析问题。

4. 实战避坑:五个让新手抓狂的 JDBC 连接问题

4.1 Public Key Retrieval is not allowed

现象:启动工程或调用接口时报Public Key Retrieval is not allowed,连带提示连接失败。

原因:MySQL 8.0 使用 caching_sha2_password 认证插件,客户端第一次连接时需要服务器的 RSA 公钥进行密码传输加密。驱动出于安全考虑,默认不允许自动获取公钥,必须要显式声明 allowPublicKeyRetrieval=true。

解决:在 JDBC URL 后追加&allowPublicKeyRetrieval=true。如果是在 DBUtil 里写死的 URL,记得改两份——一份在 DBUtil,一份在 application.properties,避免后面切换时重复踩坑。

4.2 The server time zone value is unrecognized

现象:使用 MySQL 8.0 配合驱动 8.x,连接时抛异常:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized。

原因:MySQL 8.0 驱动默认读取服务器的时区配置,而服务器时区写法在客户端这边不识别。这个报错里的乱码是字符编码转换问题,不是真的时区名称错误。

解决:JDBC URL 添加serverTimezone=Asia/Shanghai。如果你做的是全球部署,也可以设置成serverTimezone=UTC,但国内项目建议统一用 Asia/Shanghai,避免时间字段查询结果相差 8 小时。

4.3 Loading class com.mysql.jdbc.Driver 过时警告

现象:控制台出现警告Loading class 'com.mysql.jdbc.Driver' is deprecated。

原因:从 MySQL Connector/J 8.0 开始,旧的驱动类名 com.mysql.jdbc.Driver 被标记为过时,新的类名改为 com.mysql.cj.jdbc.Driver。如果 DBUtil 里 Class.forName 写的是旧类名,或者配置里 driver-class-name 用的旧写法,就会出现这个警告。

解决:把驱动类名统一改为com.mysql.cj.jdbc.Driver。如果升级不了驱动,也可以用旧类名继续跑,但建议顺手改掉,一行代码的事,免得后面排查问题时被误导。

4.4 SQLException: Access denied for user

现象:连接时提示Access denied for user 'root'@'localhost' (using password: YES)。

原因:第一可能是数据库账号密码确实不对;第二是 root 账号的 host 限制不匹配——MySQL 用户表里有 host 字段,root 可能只允许 localhost 登录;第三是密码里有特殊字符被 URL 解析吃掉。

解决:先在命令行用同样的账号密码直接试连 MySQL,定位是账号问题还是代码问题。如果命令行能连上但代码连不上,去检查 JDBC URL 里是否包含特殊字符且未被编码。命令行都连不上,就用 root 账户在 MySQL 里执行ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';重置。

4.5 中文乱码:写入正常但查询显示问号

现象:插入中文字符成功,但查询出来全是 ??,或者反过来。

原因:连接层面 characterEncoding=utf8 没设置,导致字节流按默认编码解析。也可能是 MySQL 服务端字符集本身就是 latin1,服务端压根不存储中文。

解决:JDBC URL 加characterEncoding=utf8,同时确认 MySQL 字符集配置。执行SHOW VARIABLES LIKE 'character_set%';查看服务端 charset 配置,如果是 latin1,修改 my.cnf 里的 character-set-server=utf8mb4 后重启服务。这个坑在本地开发环境经常出现,因为 MySQL 安装时默认字符集选的是系统语言,而中文 Windows 下可能装出 gbk 环境。

5. 把 JDBC 直连改造成连接池:一个必做的进阶动作

资源包里的直连方案适合学习和做小型 Demo,但如果要做课程设计答辩或给自己的小项目做基础,建议做一次改造——引入 HikariCP 连接池。做法是在 pom.xml 里加上 spring-boot-starter-jdbc,这个 starter 会传递引入 HikariCP,然后删掉 DBUtil 里手动管理连接的逻辑,改为注入 DataSource:

@Repository public class UserDao { @Autowired private DataSource dataSource; public List<Map<String, Object>> findAll() { String sql = "SELECT id, username, email, create_time FROM t_user"; List<Map<String, Object>> list = new ArrayList<>(); try (Connection conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { while (rs.next()) { Map<String, Object> map = new HashMap<>(); map.put("id", rs.getInt("id")); map.put("username", rs.getString("username")); map.put("email", rs.getString("email")); list.add(map); } } catch (SQLException e) { e.printStackTrace(); } return list; } }

改动逻辑是:不再每次手动调 DBUtil.getConnection(),而是从 DataSource 获取连接;不再写 finally 里的 close,而是用 try-with-resources 语法自动释放。HikariCP 默认会管理连接的生命周期、空闲回收、最大连接数,连接复用率大幅提高。同时还可以在 application.properties 里调整连接池参数:

spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=30000 spring.datasource.hikari.connection-timeout=30000

maximum-pool-size 是最大连接数,不是越大越好。MySQL 默认最大连接数是 151,如果应用实例多,每个实例都开 50 个连接,很容易把数据库连接数打满。个人经验是单实例 10-20 个连接足够支撑日常流量,如果压测发现有连接等待,再逐步调高而不是一步到位。

改造完成后,这套“SpringBoot + JDBC + MySQL”的工程就不再是只能跑通的 Demo,而是一个能拿去做课程设计、能上测试环境的半成品项目。如果你后面想再进一步,还可以把 SQL 拼接改成 JdbcTemplate,那就是另一套写法了。但不管怎么改,对 JDBC 这层的理解越扎实,后面学任何 ORM 框架都轻松不少——MyBatis 的 .#{} 参数占位原理,Spring Data JPA 的持久化上下文机制,底层本质上都在和你现在手写的这些代码打交道。

我每次拆这种资源包,拿到手都会先做一遍“配置审查”:看 pom.xml 里的版本号、看 DBUtil 里的连接串、看建表脚本的字符集。这三处不出问题,工程基本能一次跑通;这三处只要有一个埋雷,新手能折腾一整天。从那以后我拿到任何 SpringBoot 集成数据库的资源,都强制走一遍这个流程。希望这次的拆解,能让你的环境配置少走几段弯路。

本文还有配套的精品资源,点击获取

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

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

立即咨询