msyql存儲數據時字段被截斷


關於mysql中字段類型為text文本存儲json格式數據,字段被截斷的問題

背景:

  1. 字段類型 MEDIUMTEXT

  2. 確定存儲內容5548個字符,換算為字節不超過16M

  3. 數據庫內已經存在更長內容的存儲成功,短的內容存儲失敗

  4. 有幾率出現截斷概率,

  5. 日志看入庫前參數json都是完整的,入庫后內容被截斷,導致前端讀取數據結構解析失敗而報錯

發生這種情況的原因有兩種可能:

1. 建表時數據庫字段設置長度不足

  • 當輸入內容的字符長度大於當前字段設置長度時,數據庫會自動截斷內容
  • 字段類型以下幾種:

  • 字符串類型

類型 范圍 說明  
Char(N) [ binary] N=1~255 個字節 binary :分辨大小寫 固定長度 std_name cahr(32) not null
VarChar(N) [binary] N=1~255 個字節 binary :分辨大小寫 可變長度 std_address varchar(256)
TinyBlob 最大長度255個字節(2^8-1) Blob (Binary large objects) 儲存二進位資料,且有分大小寫 memo text not null
TinyText 最大長度255個字節(2^8-1)
Blob 最大長度65535個字節(2^16-1)
Text 最大長度65535個字節(2^16-1)
MediumBlob 最大長度 16777215 個字節(2^24-1)
MediumText 最大長度 16777215 個字節(2^24-1
LongBlob 最大長度4294967295個字節 (2^32-1)
LongText 最大長度4294967295個字節 (2^32-1)
Enum 集合最大數目為65535 列舉(Enumeration),Enum單選、Set復選 sex enum(1,0) habby set(‘玩電玩’,’睡覺’,’看電影’,’聽音樂’)
Set 集合最大數目為64
  • 數字/數值類型
類型 范圍 說明
TinyInt[M] [UNSIGNED] -128~127 UNSIGNED : 0~255 num tinyint unsigned
SmallInt[M] [UNSIGNED] -32768~32767 UNSIGNED :0~ 65535  
MediumInt[M] [UNSIGNED] -8388608~8388607 UNSIGNED :0~16777215  
Int[M] [UNSIGNED] -2^31~2^31-1 UNSIGNED : 0~2^32  
BigInt[M] [UNSIGNED] -2^63~2^63-1 UNSIGNED : 0~2^64  
Float [(M,D)] -3.4E+38~3.4E+38( 約 )

注: M 為長度, D 為小數,Float 4 bytes,Double 8 bytes Double [(M,D)] -1.79E+308~1.79E+308( 約 )Decimal [(M,D)] 辨別ZeroFill:當宣告關鍵字ZeroFill為自動填滿0,如 000021

  • 日期時間類型
類型 范圍
Date 日期(yyyy-mm-dd)
Time 時間(hh:mm:ss)
DateTime 日期與時間組合(yyyy-mm-dd hh:mm:ss)
TimeStamp yyyymmddhhmmss
Year 年份yyyy
  • 根據計算轉換字符長度可知,並沒有超過長度限制,故此種原因排除

2. 字符編碼格式數據庫不支持

  • 原數據庫字符集設置為CHARSET=utf8,有些數據編碼格式例如emoji的表情符號mysql 中的utf8並不支持
  • 據官方文檔的解釋:

    mysql 支持的 utf8 編碼最大字符長度為 3 字節,如果遇到 4 字節的寬字符就會插入異常了。三個字節的 UTF-8 最大能編碼的 Unicode 字符是 0xffff,也就是 Unicode 中的基本多文種平面(BMP)。

  • 也就是說,任何不在基本多文本平面的 Unicode字符,都無法使用 Mysql 的 utf8 字符集存儲。包括 Emoji 表情(Emoji 是一種特殊的 Unicode 編碼,常見於 ios 和 android 手機上),和很多不常用的漢字,以及任何新增的 Unicode 字符等等。

  • 觀察日志數據發現linux下打印出的日志存在類似 <u+1f44d> 樣式的字符,屬於unicode編碼的特殊字符,文本內容也是在此截斷的,由此可以判斷為字符編碼格式問題

3. 解決方案

3.1 升級 mysql 版本,並將utf8字符集升級到utf8mb4

升級你的 mysql 到 5.5.3 之后即可,查看當前環境版本:

select version();
  • MySQL在5.5.3之后增加了這個utf8mb4的編碼,mb4就是most bytes 4的意思,專門用來兼容四字節的unicode。好在utf8mb4是utf8的超集,除了將編碼改為utf8bp4外不需要做其他轉換。當然,為了節省空間,一般情況下使用utf8也就夠了。
  • 所以好的技術就是,采用對當前而言最好的解決方案,然后再逐步迭代滿足新的需求。

3.1.1 直接修改表結構

--修改數據庫字符集
ALTER DATABASE test CHARACTER SET = utf8mb4;
--修改表字符集
alter table test convert to character set utf8mb4;
--修改字符字符集
ALTER TABLE `test` CHANGE COLUMN `name` `name` varchar(12) CHARACTER SET utf8mb4;

3.1.2 修改數據庫默認配置

[client]
default-character-set = utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
[mysql]
default-character-set = utf8mb4

3.2 修改數據庫字段類型

修改字段類型為二進制存儲,通過樣可以達到目的,進行兼容

--修改字符字符集
ALTER TABLE `test` CHANGE COLUMN `name` `name` MediumBlob ;

3.3 強行過濾掉生僻字符串

  • 從業務和技術的角度綜合考慮,可以做個折中,將生僻字符串提前過濾掉,因為這類字符串本來就使用的很少,即使存進數據庫了,展示、查詢的時候也會多少有其它的問題,不如直接過濾掉,mysql 不支持四字節的 utf8 一方面可能是歷史包袱,另一方面估計也是為了省空間。

有意者可以進行測試

  1. 先向在數據庫中建表以utf8字符集,字段設置為二進制文本類型或者

     CREATE TABLE `ts_test` ( `id` int(10) NOT NULL, `content` text NOT NULL CHARACTER SET utf8mb4, --或者 `content` BLOB NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
  2. 插入表情符號emoji

     insert into ts_test ('id','content') values (1,'aaaaaaaa👍aaaaaaaa')
    
  3. 修改字段類型為普通為類型,就會發現內容從表情符開始被截斷

     ALTER TABLE `test` CHANGE COLUMN `content` `content` text not null;
    
  4. 然后再查詢該條數據,就會發現表情符后面的內容不見了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM