国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

沒想到,JDBC 驅(qū)動會偷偷修改 sql_mode 的會話值

這篇具有很好參考價值的文章主要介紹了沒想到,JDBC 驅(qū)動會偷偷修改 sql_mode 的會話值。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

最近碰到一個 case,值得分享一下。

現(xiàn)象就是一個 update 操作,在 mysql 客戶端中執(zhí)行提示 warning,但在 java 程序中執(zhí)行卻又報錯。

問題重現(xiàn)

mysql>?create?table?test.t1(id?int?primary?key,?c1?datetime);
Query?OK,?0?rows?affected?(0.01?sec)

mysql>?insert?into?test.t1?values(1,now());
Query?OK,?1?row?affected?(0.00?sec)

mysql>?update?test.t1?set?c1=str_to_date('2024-02-23?01:01:01.0','%Y-%m-%d?%H:%i:%s')?where?id=1;
Query?OK,?1?row?affected,?1?warning?(0.00?sec)
Rows?matched:?1??Changed:?1??Warnings:?1

mysql>?show?warnings;
+---------+------+-------------------------------------------------------------+
|?Level???|?Code?|?Message?????????????????????????????????????????????????????|
+---------+------+-------------------------------------------------------------+
|?Warning?|?1292?|?Truncated?incorrect?datetime?value:?'2024-02-23?01:01:01.0'?|
+---------+------+-------------------------------------------------------------+
1?row?in?set?(0.00?sec)

mysql>?select?*?from?test.t1;
+----+---------------------+
|?id?|?c1??????????????????|
+----+---------------------+
|??1?|?2024-02-23?01:01:01?|
+----+---------------------+
1?row?in?set?(0.00?sec)

update 語句中使用STR_TO_DATE函數(shù)將字符串轉(zhuǎn)換為日期時間格式。

但因為這個格式字符串'%Y-%m-%d %H:%i:%s'沒有對日期字符串中的毫秒部分.0進行解析,所以這一部分會被 truncate 掉。

可以看到,該語句在 mysql 客戶端中執(zhí)行時沒有報錯,只是提示 warning。

同樣的 SQL,在下面這段 java 代碼中跑卻直接報錯。

package?com.example;
import?java.sql.Connection;
import?java.sql.DriverManager;
import?java.sql.SQLException;
import?java.sql.Statement;

public?class?JdbcTest?{

????private?static?final?String?JDBC_URL?=?"jdbc:mysql://10.0.0.198:3306/information_schema";
????private?static?final?String?USER?=?"root";
????private?static?final?String?PASSWORD?=?"123456";

????public?static?void?main(String[]?args)?{
????????try?(Connection?connection?=?DriverManager.getConnection(JDBC_URL,?USER,?PASSWORD))?{
????????????try?(Statement?statement?=?connection.createStatement())?{
????????????????String?updateQuery?=?"UPDATE?test.t1?SET?c1?=?STR_TO_DATE('2024-02-23?01:01:01.0',?'%Y-%m-%d?%H:%i:%s')?WHERE?id=1";
????????????????int?rowsAffected?=?statement.executeUpdate(updateQuery);
????????????????System.out.println("Rows?affected:?"?+?rowsAffected);
????????????}
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????}
}
#?java?-jar?target/jdbc-test-1.0-SNAPSHOT-jar-with-dependencies.jar
com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:?Data?truncation:?Truncated?incorrect?datetime?value:?'2024-02-23?01:01:01.0'
????????at?com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:104)
????????at?com.mysql.cj.jdbc.StatementImpl.executeUpdateInternal(StatementImpl.java:1337)
????????at?com.mysql.cj.jdbc.StatementImpl.executeLargeUpdate(StatementImpl.java:2112)
????????at?com.mysql.cj.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1247)
????????at?com.example.JdbcTest.main(JdbcTest.java:17)

問題根因

剛開始以為這個報錯跟 sql_mode 有關(guān),但實際上這個實例的 sql_mode 為空。

mysql>?show?global?variables?like?'%sql_mode%';
+---------------+-------+
|?Variable_name?|?Value?|
+---------------+-------+
|?sql_mode??????|???????|
+---------------+-------+
1?row?in?set?(0.00?sec)

所以,一開始就排除了 sql_mode 的可能性。

但萬萬沒想到,JDBC 驅(qū)動會偷偷修改 sql_mode 的會話值。

在上面的 java 程序中加了一段代碼,用來打印 sql_mode 的會話值。

ResultSet?resultSet?=?statement.executeQuery("SELECT?@@SESSION.sql_mode");
if?(resultSet.next())?{
????String?sqlModeValue?=?resultSet.getString(1);
????System.out.println("Current?sql_mode?value:?"?+?sqlModeValue);
}

結(jié)果發(fā)現(xiàn)當前會話的 sql_mode 竟然是STRICT_TRANS_TABLES。

Current?sql_mode?value:?STRICT_TRANS_TABLES

STRICT_TRANS_TABLES就是導(dǎo)致 update 操作報錯的罪魁禍首!

這一點,很容易在 mysql 客戶端中驗證出來。

mysql>?set?session?sql_mode='STRICT_TRANS_TABLES';
Query?OK,?0?rows?affected,?1?warning?(0.00?sec)

mysql>?update?test.t1?set?c1=str_to_date('2024-02-23?01:01:01.0','%Y-%m-%d?%H:%i:%s')?where?id=1;
ERROR?1292?(22007):?Truncated?incorrect?datetime?value:?'2024-02-23?01:01:01.0'

所以,問題來了, sql_mode 是在哪里修改的?

sql_mode 是在哪里修改的?

分析 JDBC 驅(qū)動代碼,發(fā)現(xiàn)會話的 sql_mode 是在setupServerForTruncationChecks中修改的。

該方法是在連接建立后,初始化時調(diào)用的。

其主要作用是檢查當前會話的 sql_mode 是否包含STRICT_TRANS_TABLES,如果不包含,則會通過?SET?命令修改當前會話的 sql_mode,使其包含STRICT_TRANS_TABLES

//?src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionImpl.java
private?void?setupServerForTruncationChecks()?throws?SQLException?{
????synchronized?(getConnectionMutex())?{
????????//?獲取?JDBC?驅(qū)動程序配置中的?jdbcCompliantTruncation?屬性
????????RuntimeProperty<Boolean>?jdbcCompliantTruncation?=?this.propertySet.getProperty(PropertyKey.jdbcCompliantTruncation);
????????if?(jdbcCompliantTruncation.getValue())?{
????????????//?獲取當前會話的?sql_mode
????????????String?currentSqlMode?=?this.session.getServerSession().getServerVariable("sql_mode");
????????????//?檢查?sql_mode?中是否包含?STRICT_TRANS_TABLES?選項
????????????boolean?strictTransTablesIsSet?=?StringUtils.indexOfIgnoreCase(currentSqlMode,?"STRICT_TRANS_TABLES")?!=?-1;
????????????//?如果?sql_mode?為空,或長度為?0,或不包含?STRICT_TRANS_TABLES?選項,
????????????//?則構(gòu)建?SET?sql_mode?語句,將?STRICT_TRANS_TABLES?添加到?sql_mode?中
????????????if?(currentSqlMode?==?null?||?currentSqlMode.length()?==?0?||?!strictTransTablesIsSet)?{
????????????????StringBuilder?commandBuf?=?new?StringBuilder("SET?sql_mode='");

????????????????if?(currentSqlMode?!=?null?&&?currentSqlMode.length()?>?0)?{
????????????????????commandBuf.append(currentSqlMode);
????????????????????commandBuf.append(",");
????????????????}
?????
????????????????commandBuf.append("STRICT_TRANS_TABLES'");
????????????????//?執(zhí)行?SET?sql_mode?語句
????????????????this.session.execSQL(null,?commandBuf.toString(),?-1,?null,?false,?this.nullStatementResultSetFactory,?null,?false);

????????????????jdbcCompliantTruncation.setValue(false);?//?server's?handling?this?for?us?now
????????????}?else?if?(strictTransTablesIsSet)?{
????????????????//?如果?sql_mode?中包含?STRICT_TRANS_TABLES?選項,則不做任何調(diào)整
????????????????//?We?didn't?set?it,?but?someone?did,?so?we?piggy?back?on?it
????????????????jdbcCompliantTruncation.setValue(false);?//?server's?handling?this?for?us?now
????????????}
????????}
????}
}

所以,盡管 mysql 服務(wù)端的 sql_mode 為空,但由于 JDBC 驅(qū)動將會話的 sql_mode 調(diào)整為了STRICT_TRANS_TABLES,最后還是導(dǎo)致 update 操作報錯。

如何解決 java 程序中執(zhí)行報錯的問題

很簡單,在 JDBC URL 中將jdbcCompliantTruncation屬性設(shè)置為 false。

jdbc:mysql://10.0.0.198:3306/information_schema?jdbcCompliantTruncation=false

除此之外,也可修改 java 代碼,在 update 操作之前顯式設(shè)置 sql_mode 的會話值,如,

statement.execute("SET?@@SESSION.sql_mode?=?''");
String?updateQuery?=?"UPDATE?test.t1?SET?c1?=?STR_TO_DATE('2024-02-23?01:01:01.0',?'%Y-%m-%d?%H:%i:%s')?WHERE?id=1";

但這種方式對應(yīng)用代碼有侵入,不建議這么做。

實際上,JDBC 驅(qū)動支持在 URL 中修改參數(shù)的會話值。

在 URL 中修改參數(shù)的會話值,有以下好處:

  • 無需在每次 SQL 操作之前顯式執(zhí)行設(shè)置語句。這使得配置變更更為集中化,更容易管理和維護。

  • 避免了對應(yīng)用代碼的直接侵入,提高了代碼的可維護性和靈活性。

JDBC 驅(qū)動中如何修改參數(shù)的會話值

從 mysql-connector-java 3.1.8 開始,支持通過sessionVariables屬性修改 MySQL 參數(shù)的會話值。語法如下:

sessionVariables=variable_name1=variable_value1,variable_name1=variable_value2...variable_nameN=variable_valueN

多個參數(shù)之間使用逗號或者分號隔開。

看下面這個示例,同時修改 explicit_defaults_for_timestamp,group_concat_max_len 和 sql_mode 的會話值。

JDBC_URL?=?"jdbc:mysql://10.0.0.198:3306/information_schema?sessionVariables=explicit_defaults_for_timestamp=OFF,group_concat_max_len=2048,sql_mode='NO_ZERO_IN_DATE,NO_ZERO_DATE'"

注意,如果jdbcCompliantTruncation為 true(默認值),即使sessionVariables中設(shè)置的 sql_mode 不包含STRICT_TRANS_TABLES,最終生效的 sql_mode 的會話值還是會包含STRICT_TRANS_TABLES。

之所以會這樣,主要是因為sessionVariables的設(shè)置先于setupServerForTruncationChecks。

JDBC 驅(qū)動為什么要修改 sql_mode 的會話值

這個實際上是 JDBC 規(guī)范的要求。

Connector/J issues warnings or throws?DataTruncation?exceptions as is required by the JDBC specification, unless the connection was configured not to do so by using the property?jdbcCompliantTruncation?and setting it to?false.文章來源地址http://www.zghlxwxcb.cn/news/detail-837785.html

參考資料

  1. https://docs.oracle.com/cd/E17952_01/connector-j-8.0-en/connector-j-reference-type-conversions.html
  2. https://dev.mysql.com/doc/connector-j/en/connector-j-connp-props-session.html

到了這里,關(guān)于沒想到,JDBC 驅(qū)動會偷偷修改 sql_mode 的會話值的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 沒想到還有這種騷操作~如何使用Golang實現(xiàn)無頭瀏覽器截圖?

    在Web開發(fā)中,有時需要對網(wǎng)頁進行截圖,以便進行頁面預(yù)覽、測試等操作。 而使用無頭瀏覽器來實現(xiàn)截圖功能,可以避免手動操作的繁瑣和不穩(wěn)定性。 這篇文章將介紹: 使用Golang進行無頭瀏覽器的截圖,輕松實現(xiàn)頁面預(yù)覽、測試和模擬用戶操作。 這篇文章發(fā)完,有朋友在朋

    2024年02月05日
    瀏覽(25)
  • 真沒想到??!無需服務(wù)器,五分鐘部署公眾號機器人

    真沒想到??!無需服務(wù)器,五分鐘部署公眾號機器人

    大家好,我是編程哥。一個尋求破圈,不斷淬煉自己的人,關(guān)注我一起進步。 目前各大模型都比較火,作為一名程序員,對大模型的了解也是蠢蠢欲動,尤其是對于機器人自動問答這一項。所以在朋友的推薦下,了解了一個無需服務(wù)器,快速搭建公眾號機器人的教程,現(xiàn)在分

    2024年02月03日
    瀏覽(22)
  • 作為所有類的頂層父類,沒想到Object的魔力如此之大!

    作為所有類的頂層父類,沒想到Object的魔力如此之大!

    在上一篇博文中我們提到了Java面向?qū)ο蟮乃拇筇匦裕渲姓劶啊俺橄蟆碧匦詴r做了一個引子,引出今天的主人公Object,作為所有類的頂級父類,Object被視為是James.Gosling的哲學思考,它高度概括了事務(wù)的自然與社會行為。 跟進Object類的源碼中我們可以看到,類的注釋中對它做

    2024年02月01日
    瀏覽(20)
  • 云安全_什么是云,云計算的本質(zhì),沒想到一個Handler還有中高級幾種問法

    云安全_什么是云,云計算的本質(zhì),沒想到一個Handler還有中高級幾種問法

    是將計算機終端系統(tǒng)進行虛擬化,以達到桌面使用的安全性和靈活性??梢酝ㄟ^任何設(shè)備,在任何地點,任何時間通過網(wǎng)絡(luò)訪問屬于我們個人的桌面系統(tǒng)。 存儲虛擬化 是對存儲硬件資源進行抽象化表現(xiàn)。 網(wǎng)絡(luò)虛擬化 網(wǎng)絡(luò)虛擬化就是在一個物理網(wǎng)絡(luò)上模擬出多個邏輯網(wǎng)絡(luò)來。

    2024年04月13日
    瀏覽(25)
  • [鏈表OJ題 8] 用棧實現(xiàn)隊列,沒想到你小子的基礎(chǔ)這么好,這么快就做對了

    [鏈表OJ題 8] 用棧實現(xiàn)隊列,沒想到你小子的基礎(chǔ)這么好,這么快就做對了

    目錄 題目來源: 代碼實現(xiàn): 思路分析: 實現(xiàn)過程: 力扣 - 232.用棧實現(xiàn)隊列 題目描述: 我們這里的棧已經(jīng)寫好了,如果對棧還不是很懂的可以看看這篇文章:CSDN - [數(shù)據(jù)結(jié)構(gòu) -- C語言] 棧(stack) 我們知道 隊列的特性:先入先出;棧的特性:先入后出。 因此我們定義兩個棧

    2024年02月06日
    瀏覽(32)
  • 5年測試經(jīng)驗怎么著我也能要個20K吧?沒想到被阿里P8問傻了

    都說金三銀四是跳槽漲薪季,我也是著急忙慌的準備簡歷—— 5年軟件測試經(jīng)驗,可獨立測試大型產(chǎn)品項目,熟悉項目測試流程…薪資要求?5年測試經(jīng)驗起碼能要個20K吧? 我加班肝了一頁半簡歷,投出去一周,面試電話倒是不少,自信滿滿去面試,現(xiàn)場被問了這么幾個問題—

    2024年02月08日
    瀏覽(19)
  • 5年測試經(jīng)驗怎么著我也能要個20K吧?沒想到被阿里P8問傻了····

    5年測試經(jīng)驗怎么著我也能要個20K吧?沒想到被阿里P8問傻了····

    都說金三銀四是跳槽漲薪季,我也是著急忙慌的準備簡歷—— 5年軟件測試經(jīng)驗,可獨立測試大型產(chǎn)品項目,熟悉項目測試流程…薪資要求?5年測試經(jīng)驗起碼能要個20K吧? 我加班肝了一頁半簡歷,投出去一周,面試電話倒是不少,自信滿滿去面試,現(xiàn)場被問了這么幾個問題—

    2024年02月08日
    瀏覽(21)
  • 看了mysql8.0官網(wǎng),發(fā)現(xiàn)set sql_mode原來有可以不用修改my.cnf或mysqld-auto.cnf就可以持久化系統(tǒng)變量的方式

    @@GLOBAL.sql_mode: 全局級別的設(shè)置,影響所有新的客戶端連接。通常需要具有高級權(quán)限才能修改,且修改后對尚未建立連接的新會話生效,對當前已存在的會話無效。MySQL服務(wù)器重啟后,如果沒有在配置文件中永久設(shè)定,全局設(shè)置將恢復(fù)到服務(wù)器啟動時的默認值或配置文件中的設(shè)

    2024年04月15日
    瀏覽(29)
  • DBeaver連接mysql時報錯com.mysql.cj.jdbc.Driver的解決方法【修改驅(qū)動下載的maven地址和重新下載驅(qū)動】

    DBeaver連接mysql時報錯com.mysql.cj.jdbc.Driver的解決方法【修改驅(qū)動下載的maven地址和重新下載驅(qū)動】

    網(wǎng)上下載了最新版本的DBeaver軟件,但是鏈接mysql的時候驅(qū)動下載失敗,所以就報下面錯誤了 原因:其實就是軟件自帶的下載maven地址不能用,如果你有看下載驅(qū)動界面,會看到提示的報錯是超時。 所以就是因為驅(qū)動沒下載成功所以鏈接才會有這個報錯的。 位置如下【我下面

    2024年02月12日
    瀏覽(97)
  • 偷偷告訴你Linux 修改系統(tǒng)時間的兩種方式

    偷偷告訴你Linux 修改系統(tǒng)時間的兩種方式

    1、手動修改 通過相關(guān)工具來手動修改系統(tǒng)的時間。 2、自動同步 使用NTP自動同步系統(tǒng)時間。 1、date工具 作用:顯示和設(shè)置系統(tǒng)時間 選項: 時間格式: 例如:顯示年月日時分秒 只修改年月日: 只修改時分秒: 全部都改: 說明: 使用date命令修改的時間是 臨時生效 的,重

    2024年02月09日
    瀏覽(16)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包