首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 整型溢出行為差異詳解:5.1 默默截斷 vs 5.5+ 顯式報錯

     編輯:MySQL 綜合教學

MySQL 整型溢出行為差異詳解

MySQL 不同版本對整型溢出的處理機制存在關鍵差異:5.1 默默回滾/截斷,5.5+ 拋出錯誤中斷。這不僅導致主從同步中斷,更可能引發積分、金額等核心業務邏輯錯誤。本文通過實測對比,揭示版本差異根因,給出升級與應用層雙重防護方案。

MySQL 整型範圍速查表

類型儲存有符號範圍無符號範圍
TINYINT1 byte-128 ~ 1270 ~ 255
SMALLINT2 bytes-32,768 ~ 32,7670 ~ 65,535
MEDIUMINT3 bytes-8,388,608 ~ 8,388,6070 ~ 16,777,215
INT4 bytes-2,147,483,648 ~ 2,147,483,6470 ~ 4,294,967,295
BIGINT8 bytes-9.22E18 ~ 9.22E180 ~ 1.84E19

注意:MySQL 內部運算會將整型提升為 BIGINT 計算,故溢出邊界以 BIGINT 為準。

實測對比:5.1 vs 5.5/5.6/5.7

測試 1:無符號減法溢出

SELECT CAST(0 AS UNSIGNED) - 1;
版本結果行為
5.118446744073709551615 (最大無符號值)靜默回滾 (wrap-around)
5.5+ERROR 1690 (22003): BIGINT UNSIGNED value is out of range顯式報錯中斷

測試 2:有符號加法溢出

SELECT 9223372036854775807 + 1;
版本結果行為
5.1-9223372036854775808 (最小有符號值)靜默回滾
5.5+ERROR 1690 (22003): BIGINT value is out of range顯式報錯中斷

業務影響場景

  • 積分/餘額扣減:UPDATE account SET balance = balance - 100 WHERE id=1 若 balance 不足,5.1 變巨大正數,5.5+ 報錯回滾。
  • 主從不同步:主庫 5.1 寫入「回滾後值」,從庫 5.5 執行同步 SQL 報錯中斷同步,導致數據不一致。
  • 早期作弊案例:利用 5.1 溢出特性將 Q幣/積分變為巨大值,屬經典安全漏洞。

解決方案:雙軌防護

方案一:升級資料庫版本 (根治)

將所有實例升級至 MySQL 5.5+ (建議 5.7/8.0),獲得標準 SQL 模式下的溢出報錯保護。主從版本必須一致,避免混合部署。

方案二:應用層/資料庫層雙重檢查 (深度防禦)

  1. 應用層前置校驗:扣減前 SELECT balance FROM account WHERE id=1 FOR UPDATE,判斷 balance >= amount 再執行扣減。
  2. 資料庫約束:給金額欄位加 CHECK (balance >= 0) (8.0.16+ 支援) 或觸發器攔截負值。
  3. 使用 DECIMAL 替代整型:金額類業務強制 DECIMAL(18,2),避免整型溢出且精度精確。
  4. 啟用嚴格 SQL 模式:SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION',強化數據校驗。

補充:字段數據溢出的通用排查

若遇到「Data truncated for column」或數值異常:

  • 檢查 SHOW WARNINGS 獲取截斷詳情。
  • 對比源數據範圍與目標欄位定義 (DESC tbl)。
  • 使用 CAST(val AS UNSIGNED) 或 CAST(val AS DECIMAL(30,0)) 顯式轉型觀察行為。

總結

MySQL 5.1 的靜默溢出行為是重大缺陷,5.5+ 修正為標準報錯機制。核心業務務必升級至 5.7/8.0,並建立「應用層校驗 + 資料庫約束 + 嚴格模式」三層防線,從根源杜絕整型溢出引發的數據災難。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved