<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一條詭異的insert語句

          共 3091字,需瀏覽 7分鐘

           ·

          2021-11-26 21:39

          作者 | 天士夢

          來源 | https://www.cnblogs.com/cchust/p/4601536.html

          問題背景

          有同事反饋在mysql上面執(zhí)行一條普通的insert語句,結(jié)果報錯,

          execute failed due to >>> Incorrect string value: '\xA1;offl...' for column 'biz_info' at row 1

          經(jīng)過半天的折騰,終于搞清楚了來龍去脈,這里簡單給大家分享下。為了方便說明,我將測試例子中的表和語句簡化,但不影響問題重現(xiàn)。

          問題復現(xiàn)

          連接字符集:UTF8

          表結(jié)構(gòu):

          CREATE TABLE `ggg` (
            `id` int(11DEFAULT NULL,
            `c` varchar(100DEFAULT NULL
          ENGINE=InnoDB DEFAULT CHARSET=gbk;
          root@test 06:13:48>insert into ggg values(1,concat('cardName:校園網(wǎng)',char(59),'offlineCardType:campus'));
          Query OK, 1 row affected, 1 warning (2.51 sec)
          root@test 06:14:36>show warnings\G
          *************************** 1. row ***************************
          LevelWarning
          Code: 1366
          Message: Incorrect string value'\x91;offl...' for column 'c' at row 1 

          查看結(jié)果

          root@test 06:16:06>select * from ggg where id=1;
          *************************** 1. row ***************************
          id: 1
          c: cardName:鏍″洯緗

          問題分析

          從報錯的結(jié)果來看,感覺是字符集轉(zhuǎn)換引起的問題,而且由于連接串的字符集是UTF8,表的字符集是GBK,更容易引起懷疑。但是,即使是字符集轉(zhuǎn)換,也不應(yīng)該導致插入報錯,因為語句中的中文字符“校園網(wǎng)"都是普通漢字,UTF8->GBK不應(yīng)該存在問題。

          那我們在回過頭來看看insert語句,唯一特殊的是使用了concat和char兩個函數(shù)。會不會跟這兩個函數(shù)有關(guān)系?char(59)實際是字符“;”,為了驗證想法,做了兩個實驗:

          將char(59)替換成';'

          insert into ggg values(1,concat('cardName:校園網(wǎng)',';','offlineCardType:campus'));

          設(shè)置連接串字符集為GBK

          insert into ggg values(1,concat('cardName:校園網(wǎng)',char(59),'offlineCardType:campus'));

          果然,兩種情況執(zhí)行結(jié)果都是OK的,查詢結(jié)果如下:

          root@test 09:22:32>select * from ggg\G
          *************************** 1. row ***************************
          id: 1
          c: cardName:鏍″洯緗
          *************************** 2. row ***************************
          id: 1
          c: cardName:校園網(wǎng);offlineCardType:campus
          *************************** 3. row ***************************
          id: 1
          c: cardName:校園網(wǎng);offlineCardType:campus

          跟蹤了下源代碼,找到了原因。char()函數(shù)返回的是一個binary類型字符串,在進行concat時,會導致'cardName:校園網(wǎng)'字符串到binary的轉(zhuǎn)換。轉(zhuǎn)換前,mysql將字符串‘cardName:校園網(wǎng)’看作是9個英文字符和3個漢字字符;轉(zhuǎn)換后,mysql將其看作是18個字節(jié)的二進制串,其中,UTF8字符集的三個漢字“校園網(wǎng)”占了9個字節(jié)。由于目標表字符集是GBK,因此在入庫時,還會發(fā)生一次binary到GBK的轉(zhuǎn)碼,“校園網(wǎng)”的二級制編碼是E6A0A1 E59BAD E58DA1,在轉(zhuǎn)碼過程中,由于GBK字符集只包含一個字節(jié)(編碼值<128)和二個字節(jié)的字符(漢字和特殊字符),“校園網(wǎng)”的二進制串會按照兩個字節(jié)拆分E6A0 A1E5 9BAD E58D A1,前面四個變?yōu)椤版牎鍥|”,解析到A1時,由于A1既不是單字節(jié)字符,又不能與后面的字節(jié)組成一個合法的GBK字符,導致轉(zhuǎn)換出錯。

          現(xiàn)在就很好解釋為啥改變語句后,兩種情況都OK了。第一種情況,將char(59)直接替換成‘;’,由于不涉及UF8到binary的轉(zhuǎn)換,只有utf8到gbk轉(zhuǎn)碼的過程,這個轉(zhuǎn)換是OK的,不會出現(xiàn)亂碼;第二種情況,將連接串的字符集設(shè)置為GBK,那么會涉及GBK到binary的轉(zhuǎn)換,然后再從binary轉(zhuǎn)換到GBK,由于整個轉(zhuǎn)換過程并沒有二進制數(shù)據(jù)丟失,所以也是OK的。

          問題產(chǎn)生的兩個關(guān)鍵點

          1. 連接字符集與表字符集不匹配
          2. 使用了char函數(shù)

          解決辦法

          1.char函數(shù)提供了using語法來實現(xiàn)返回特定字符集的字符串,比如:char(59 using utf8)

          2.保證連接字符集與表字符集一致。

          往期推薦

          Spring Boot 2.6之后,動態(tài)權(quán)限控制終于可以用起來了!

          浪潮編了個“謊言”舉報我們...

          Spring Boot 2.6 正式發(fā)布:循環(huán)依賴默認禁止、增加SameSite屬性...

          一文教你如何高效使用 IDEA !

          周杰倫新動作的老朋友是誰?程序員:送分題!



          技術(shù)交流群

          最近有很多人問,有沒有讀者交流群,想知道怎么加入。加入方式很簡單,有興趣的同學,只需要點擊下方卡片,回復“加群,即可免費加入我們的高質(zhì)量技術(shù)交流群!

          點擊閱讀原文,送你免費Spring Boot教程!

          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本岛国视频在线观看一区二区三区 | 日本色情视频在线 | 日韩精品在线观看免费 | 伊人操逼视频网 | 2016亚洲天堂 |