深度剖析SpringBoot框架下關(guān)于項(xiàng)目運(yùn)行時(shí)數(shù)據(jù)庫連接失敗的可能問題、解決方案
一、問題場景
在啟動(dòng)基于SpringBoot+MyBatis的圖書管理系統(tǒng)項(xiàng)目并嘗試注冊(cè)/登錄時(shí),前端頁面報(bào)錯(cuò)如下:
登錄失敗: ### 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
控制臺(tái)日志報(bào)錯(cuò)如下:
連接失?。?錯(cuò)誤類型: SQLException 錯(cuò)誤信息: Access denied for user 'root'@'localhost' (using password: YES) 可能的原因: MySQL服務(wù)未啟動(dòng) 數(shù)據(jù)庫'library'不存在 用戶名或密碼錯(cuò)誤 MySQL端口(3306)被占用或防火墻阻止 MySQL不允許遠(yuǎn)程連接(雖然這里是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)
控制臺(tái)日志的這段報(bào)錯(cuò)是我在com.example目錄下使用Lingma這個(gè)AI工具plugin部署的一個(gè)數(shù)據(jù)庫連接測(cè)試類(DatabaseConnectionTest.java)返回的信息,能夠使報(bào)錯(cuò)信息更加通俗易懂并給出一份具有優(yōu)先級(jí)的排除方案
二、問題原因
依據(jù)控制臺(tái)返回的信息,我依次排查了可能存在的問題:
1.首先從數(shù)據(jù)庫是否連接正常開始排查,測(cè)試連接是成功的(這里是一個(gè)坑)

2.隨后又在DataGrip數(shù)據(jù)庫可視化工具中檢查了library是否真實(shí)存在,答案也是肯定的

3.在排查完前兩個(gè)問題后,我在排查第三個(gè)問題時(shí)終于有了答案

這段yaml文件中的核心數(shù)據(jù)源基礎(chǔ)配置看似毫無問題,也沒有報(bào)錯(cuò)提示,但關(guān)鍵就在于password——以0開頭的密碼。我了解到,通常情況下YAML解析器會(huì)嘗試將password后面對(duì)應(yīng)的這串key解析為數(shù)字,但在某些YAML版本中,前導(dǎo)0是表示八進(jìn)制數(shù)的,也就是060711(八進(jìn)制)= 25033(十進(jìn)制),又或者被解析為整數(shù)60711(即去掉前導(dǎo)0)。而無論是哪種情況,都會(huì)導(dǎo)致配置數(shù)據(jù)庫的密碼錯(cuò)誤,這是源于YAML的類型推斷規(guī)則產(chǎn)生的。
YAML 是一種智能的類型推斷格式,它會(huì)根據(jù)值的格式自動(dòng)判斷類型:
# 這些能被解析為整數(shù)
age: 25 → Integer: 25
count: 100 → Integer: 100
# 這些能被解析為浮點(diǎn)數(shù)
price: 9.99 → Float: 9.99
rate: 0.5 → Float: 0.5
# 而這則會(huì)產(chǎn)生歧義
code: 060711 → 可能被解析為:
- 八進(jìn)制數(shù)(YAML 1.1): 25033
- 整數(shù)(去掉前導(dǎo)0): 60711
- 字符串(YAML 1.2): "060711"因此MySQL在驗(yàn)證密碼時(shí)則會(huì)接收到錯(cuò)誤數(shù)據(jù),進(jìn)而導(dǎo)致數(shù)據(jù)庫的連接失敗。
三、解決方案
一個(gè)比較顯而易見的解決方法是修改數(shù)據(jù)庫密碼使其不以0開頭,但這顯然不是一個(gè)成熟的做法,更好的解決方案是添加引號(hào):
# 無論是雙引號(hào)還是單引號(hào),都能將其解析為字符串: code: "060711" → String: "060711" code: '060711' → String: "060711"
這樣就能確定無論什么版本的YAML在解析時(shí)能夠?qū)⑵浣馕鰹樽址?/p>
四、深度剖析
看到這,似乎問題都已經(jīng)解決了,就只是一個(gè)簡單的YAML解析器在對(duì)于不夠規(guī)范的數(shù)據(jù)輸入方式的解析歧義問題。但,前面還有一個(gè)坑沒填,那就是為什么排錯(cuò)的第一步的測(cè)試連接是成功的?
這就要深究YAML規(guī)范、解析器實(shí)現(xiàn)差異以及IDE的特殊處理機(jī)制了。以下是我根據(jù)查詢到的資料進(jìn)行的總結(jié):
首先需要確認(rèn)的是,在YAML 1.1版本確實(shí)存在將"0xxx"視為八進(jìn)制的設(shè)計(jì),這在新版1.2中被修正為字符串。但關(guān)鍵在于不同解析器的兼容性處理策略。
而IDEA在測(cè)試連接時(shí)很可能做了隱式轉(zhuǎn)換。當(dāng)數(shù)據(jù)庫驅(qū)動(dòng)接收到數(shù)字密碼時(shí),多數(shù)驅(qū)動(dòng)庫會(huì)自動(dòng)執(zhí)行toString()轉(zhuǎn)換,例如MySQL JDBC在接收到數(shù)字密碼時(shí)會(huì)嘗試隱性轉(zhuǎn)換為字符串,但這個(gè)行為是不可靠的,因?yàn)樵谏a(chǎn)環(huán)境中如果配置讀取后保持?jǐn)?shù)字類型,就會(huì)導(dǎo)致連接失敗。
因此總結(jié):測(cè)試成功不等于生產(chǎn)可用。IDEA的測(cè)試連接是獨(dú)立環(huán)境,它可能使用了自己的配置解析邏輯,或者數(shù)據(jù)庫驅(qū)動(dòng)在測(cè)試連接時(shí)有更寬松的類型轉(zhuǎn)換機(jī)制——這對(duì)于生產(chǎn)環(huán)境的連接屬于向下兼容,這個(gè)現(xiàn)象反而說明生產(chǎn)環(huán)境更嚴(yán)格遵循了類型安全規(guī)范。
到此這篇關(guān)于深度剖析SpringBoot框架下關(guān)于項(xiàng)目運(yùn)行時(shí)數(shù)據(jù)庫連接失敗的可能問題、解決方案的文章就介紹到這了,更多相關(guān)SpringBoot項(xiàng)目運(yùn)行時(shí)數(shù)據(jù)庫連接失敗內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Trae配置Java環(huán)境并運(yùn)行springboot項(xiàng)目的過程
- SpringBoot項(xiàng)目Jar包使用systemctl運(yùn)行過程
- Docker部署SpringBoot項(xiàng)目,本地運(yùn)行正常,部署至服務(wù)器報(bào)錯(cuò)zip file closed問題
- SpringBoot項(xiàng)目nohup啟動(dòng)運(yùn)行日志過大的解決方案
- IDEA運(yùn)行SpringBoot項(xiàng)目的圖文教程
- SpringBoot項(xiàng)目打包成war包并部署在tomcat上運(yùn)行的操作步驟
- springboot項(xiàng)目啟動(dòng)的時(shí)候,運(yùn)行main方法報(bào)錯(cuò)NoClassDefFoundError問題
- SpringBoot配置層級(jí)錯(cuò)誤導(dǎo)致數(shù)據(jù)庫連接失敗的解決方案
- 解決springboot?druid數(shù)據(jù)庫連接池連接失敗后一直重連問題
- springboot druid數(shù)據(jù)庫連接池連接失敗后一直重連的解決方法
相關(guān)文章
Spring?Data?JPA框架的核心概念與Repository接口詳解
Spring?Data?JPA是Spring基于JPA規(guī)范的基礎(chǔ)上封裝的?套?JPA?應(yīng)?框架,可使開發(fā)者?極簡的代碼即可實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的訪問和操作,本篇我們來了解Spring?Data?JPA框架的核心概念與Repository接口2022-04-04
Java調(diào)用Coze?API詳細(xì)實(shí)現(xiàn)步驟
Coze是一款由字節(jié)跳動(dòng)推出的低代碼AI開發(fā)平臺(tái),讓非專業(yè)開發(fā)者也能輕松創(chuàng)建智能應(yīng)用,這篇文章主要介紹了Java調(diào)用Coze?API的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-01-01

