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

MySQL 整型溢出行為版本差異:5.1 靜默回滾 vs 5.5+ 顯式報錯

     編輯:MySQL 資料庫相關知識

整型範圍速查

類型存儲有符號範圍無符號範圍
TINYINT1B-128 ~ 1270 ~ 255
SMALLINT2B-32,768 ~ 32,7670 ~ 65,535
MEDIUMINT3B-8,388,608 ~ 8,388,6070 ~ 16,777,215
INT4B-2,147,483,648 ~ 2,147,483,6470 ~ 4,294,967,295
BIGINT8B-9.22e18 ~ 9.22e180 ~ 1.84e19

版本行為對比實測

測試用例

SELECT CAST(0 AS UNSIGNED) - 1;           -- 無符號下溢
SELECT 9223372036854775807 + 1;             -- 有符號上溢 (BIGINT MAX)

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)'

**SQL 執行失敗**,錯誤碼 1690 (22003),數據完整性受保護。

業務風險場景

  • 積分/餘額扣減:餘額 0 繼續扣減 → 變巨大正數(5.1)或報錯(5.5+)
  • 庫存扣減:並發超賣導致負數回滾
  • ID 生成:自增接近上限
  • 主從版本不一致:主 5.1 寫入溢出值,從 5.5 報錯中斷同步

根因:SQL 標準與實現演進

  • SQL:2003 引入「數據異常」處理
  • MySQL 5.5 開始遵循標準,拒絕靜默截斷/回滾
  • sql_mode 可控制:NO_UNSIGNED_SUBTRACTION 等

解決方案與最佳實踐

1. 應用層防護(首選)

// Java 示例
if (balance < amount) throw new InsufficientBalanceException();
balance -= amount;

2. 數據庫層約束

-- 觸發器防溢出
CREATE TRIGGER before_balance_update
BEFORE UPDATE ON account
FOR EACH ROW
BEGIN
    IF NEW.balance < 0 THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Balance cannot be negative';
    END IF;
END;

3. 類型選擇留足餘量

  • 金額用 DECIMAL(18,2) 而非整型分
  • 計數器預估峰值 × 100 選類型
  • 自增 ID 用 BIGINT(80 億年才用完)

4. 升級策略

  1. 測試環境驗證所有溢出點報錯行為
  2. 應用捕獲 Error 1690 轉為業務異常
  3. 主從同步升級:先升從庫,再切主,最後升舊主

官方文檔參考

MySQL 5.7 Reference Manual: Out-of-Range and Overflow Handling

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