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

MySQL 整型溢出行為差異:5.1 靜默回繞 vs 5.5+ 報錯截斷,升級避坑指南

     編輯:MySQL 綜合教學

背景

朋友遭遇「數據被竄改」疑雲,排查後發現是 無符號整型減法溢出導致靜默回繞。MySQL 5.1 與 5.5+ 對溢出處理機制截然不同,若主從版本混用(主 5.1、從 5.5)更會導致複製中斷。本文實測對比並給出升級建議。

整型範圍速查

類型有符號範圍無符號範圍存儲字節
TINYINT-128 ~ 1270 ~ 2551
SMALLINT-32,768 ~ 32,7670 ~ 65,5352
MEDIUMINT-8,388,608 ~ 8,388,6070 ~ 16,777,2153
INT-2,147,483,648 ~ 2,147,483,6470 ~ 4,294,967,2954
BIGINT-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,8070 ~ 18,446,744,073,709,551,6158

注意:MySQL 內部運算統一提升至 BIGINT,故以 BIGINT 為例驗證。

實測對比

MySQL 5.1(靜默回繞)

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
| 18446744073709551615    |  -- 回繞到 UNSIGNED MAX
+-------------------------+

mysql> SELECT 9223372036854775807 + 1;
+-------------------------+
| 9223372036854775807 + 1 |
+-------------------------+
| -9223372036854775808    |  -- 回繞到 SIGNED MIN
+-------------------------+

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,餘額不足時 5.1 靜默變巨款,5.5+ 直接報錯保護數據。
  • 主從混版本複製中斷:主庫 5.1 寫入回繞值,從庫 5.5 執行相同 SQL 報錯,SQL 線程停止。
  • 早期「沖 Q 幣」類漏洞:利用無符號減法回繞繞過業務檢查。

升級避坑清單

  1. 全鏈路升級:主從同步升級至 5.5+,避免混版本複製。
  2. 應用層加保護:扣減前先 SELECT ... FOR UPDATE 校驗餘額 ≥ 扣減額,再執行更新。
  3. SQL_MODE 增強:啟用 STRICT_TRANS_TABLES(5.5+ 默認開啟),強制截斷/溢出報錯。
  4. 測試驗證:升級前在測試環境跑全量回歸,重點覆蓋邊界值扣減、累加邏輯。

結語:MySQL 5.1 時代的「靜默回繞」是數據完整性的隱形殺手。業務涉及金額/積分/計數的系統,強烈建議升級至 5.5+ 並開啟嚴格模式,將溢出風險從運行時轉移到編譯/驗證階段。

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