首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 整型溢出行為版本差異:5.1 靜默回繞 vs 5.5+ 報錯攔截

     編輯:MySQL 資料庫相關知識

MySQL 5.1 對整型溢出採用靜默回繞(wrap-around),5.5+ 預設啟用嚴格模式報錯攔截。版本混用(主 5.1、從 5.5)會導致複寫中斷或資料不一致。本文實測對比並給出升級建議。

整型範圍回顧

型別有號範圍無號範圍儲存空間
TINYINT-128 ~ 1270 ~ 2551 byte
SMALLINT-32768 ~ 327670 ~ 655352 bytes
MEDIUMINT-8388608 ~ 83886070 ~ 167772153 bytes
INT-2147483648 ~ 21474836470 ~ 42949672954 bytes
BIGINT-9223372036854775808 ~ 92233720368547758070 ~ 184467440737095516158 bytes

MySQL 內部運算會轉為 BIGINT 處理,以下以 BIGINT 為例測試。

MySQL 5.1 行為(靜默回繞)

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
| 18446744073709551615    |  -- 回繞到最大無號值
+-------------------------+

mysql> SELECT 9223372036854775807 + 1;
+-------------------------+
| 9223372036854775807 + 1 |
+-------------------------+
| -9223372036854775808    |  -- 有號溢出回繞到最小值
+-------------------------+

MySQL 5.5 / 5.6 / 5.7 行為(報錯攔截)

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'

mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'

業務影響場景

  • 積分/餘額扣減:UPDATE account SET balance = balance - 100 WHERE id=1 若 balance 為 0,5.1 會變成巨大正數,5.5+ 直接報錯保護資料。
  • 主從版本不一致:主庫 5.1 寫入溢出值,從庫 5.5 執行相同 SQL 報錯,複寫中斷。
  • 應用層未捕獲異常:5.1 靜默產生髒資料,事後難以發現。

解決方案與建議

  1. 統一升級至 5.5+(建議 5.7/8.0),啟用 sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION。
  2. 應用層加入業務邊界檢查(如餘額不足拒絕扣減)。
  3. 若無法立即升級,主從版本必須一致,並在 5.1 上手動加入 SIGNAL 或觸發器攔截溢出。
  4. 資料型別選擇:無負值業務務必用 UNSIGNED,並評估上限是否足夠(如積分用 BIGINT UNSIGNED)。

核心觀念:資料庫層面的攔截是最後防線,應用層驗證是第一道防線,兩者缺一不可。

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