一、问题场景
在启动基于springboot+mybatis的图书管理系统项目并尝试注册/登录时,前端页面报错如下:
登录失败: ### error querying database. cause: org.springframework.jdbc.cannotgetjdbcconnectionexception: failed to obtain jdbc connection ### the error may exist in file [d:\develep\projects\books\target\classes\mapper\usermapper.xml] ### the error may involve com.example.mapper.usermapper.selectbyusername ### the error occurred while executing a query ### cause: org.springframework.jdbc.cannotgetjdbcconnectionexception: failed to obtain jdbc connection
控制台日志报错如下:
连接失败! 错误类型: sqlexception 错误信息: access denied for user 'root'@'localhost' (using password: yes) 可能的原因: mysql服务未启动 数据库'library'不存在 用户名或密码错误 mysql端口(3306)被占用或防火墙阻止 mysql不允许远程连接(虽然这里是localhost) java.sql.sqlexception: access denied for user 'root'@'localhost' (using password: yes) at com.mysql.cj.jdbc.exceptions.sqlerror.createsqlexception(sqlerror.java:121) at com.mysql.cj.jdbc.exceptions.sqlexceptionsmapping.translateexception(sqlexceptionsmapping.java:114) at com.mysql.cj.jdbc.connectionimpl.createnewio(connectionimpl.java:840) at com.mysql.cj.jdbc.connectionimpl.<init>(connectionimpl.java:416) at com.mysql.cj.jdbc.connectionimpl.getinstance(connectionimpl.java:237) at com.mysql.cj.jdbc.nonregisteringdriver.connect(nonregisteringdriver.java:180) at com.zaxxer.hikari.util.driverdatasource.getconnection(driverdatasource.java:144) at com.zaxxer.hikari.pool.poolbase.newconnection(poolbase.java:373)
控制台日志的这段报错是我在com.example目录下使用lingma这个ai工具plugin部署的一个数据库连接测试类(databaseconnectiontest.java)返回的信息,能够使报错信息更加通俗易懂并给出一份具有优先级的排除方案
二、问题原因
依据控制台返回的信息,我依次排查了可能存在的问题:
1.首先从数据库是否连接正常开始排查,测试连接是成功的(这里是一个坑)

2.随后又在datagrip数据库可视化工具中检查了library是否真实存在,答案也是肯定的

3.在排查完前两个问题后,我在排查第三个问题时终于有了答案

这段yaml文件中的核心数据源基础配置看似毫无问题,也没有报错提示,但关键就在于password——以0开头的密码。我了解到,通常情况下yaml解析器会尝试将password后面对应的这串key解析为数字,但在某些yaml版本中,前导0是表示八进制数的,也就是060711(八进制)= 25033(十进制),又或者被解析为整数60711(即去掉前导0)。而无论是哪种情况,都会导致配置数据库的密码错误,这是源于yaml的类型推断规则产生的。
yaml 是一种智能的类型推断格式,它会根据值的格式自动判断类型:
# 这些能被解析为整数
age: 25 → integer: 25
count: 100 → integer: 100
# 这些能被解析为浮点数
price: 9.99 → float: 9.99
rate: 0.5 → float: 0.5
# 而这则会产生歧义
code: 060711 → 可能被解析为:
- 八进制数(yaml 1.1): 25033
- 整数(去掉前导0): 60711
- 字符串(yaml 1.2): "060711"因此mysql在验证密码时则会接收到错误数据,进而导致数据库的连接失败。
三、解决方案
一个比较显而易见的解决方法是修改数据库密码使其不以0开头,但这显然不是一个成熟的做法,更好的解决方案是添加引号:
# 无论是双引号还是单引号,都能将其解析为字符串: code: "060711" → string: "060711" code: '060711' → string: "060711"
这样就能确定无论什么版本的yaml在解析时能够将其解析为字符串了
四、深度剖析
看到这,似乎问题都已经解决了,就只是一个简单的yaml解析器在对于不够规范的数据输入方式的解析歧义问题。但,前面还有一个坑没填,那就是为什么排错的第一步的测试连接是成功的?
这就要深究yaml规范、解析器实现差异以及ide的特殊处理机制了。以下是我根据查询到的资料进行的总结:
首先需要确认的是,在yaml 1.1版本确实存在将"0xxx"视为八进制的设计,这在新版1.2中被修正为字符串。但关键在于不同解析器的兼容性处理策略。
而idea在测试连接时很可能做了隐式转换。当数据库驱动接收到数字密码时,多数驱动库会自动执行tostring()转换,例如mysql jdbc在接收到数字密码时会尝试隐性转换为字符串,但这个行为是不可靠的,因为在生产环境中如果配置读取后保持数字类型,就会导致连接失败。
因此总结:测试成功不等于生产可用。idea的测试连接是独立环境,它可能使用了自己的配置解析逻辑,或者数据库驱动在测试连接时有更宽松的类型转换机制——这对于生产环境的连接属于向下兼容,这个现象反而说明生产环境更严格遵循了类型安全规范。
到此这篇关于深度剖析springboot框架下关于项目运行时数据库连接失败的可能问题、解决方案的文章就介绍到这了,更多相关springboot项目运行时数据库连接失败内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论