參數定義與預設行為
- 參數:
autocommit
- 預設值:
ON(1)——每條 SQL 執行完**立即自動提交**
- 作用域: `SESSION` / `GLOBAL` 均可動態修改
- 查看:
SHOW VARIABLES LIKE 'autocommit';
兩種模式對比
| 模式 | 設定值 | 行為 | 適用場景 |
| 自動提交 | autocommit=1 | 單條 DML 即時生效,無法回滾 | 唯讀查詢、單條獨立寫入、非關鍵業務 |
| 手動提交 | autocommit=0 | 需顯式 COMMIT/ROLLBACK,多條 DML 形成一個事務 | 轉帳、訂單、庫存扣減等需 ACID 的業務 |
關鍵區別:SET autocommit=0 vs START TRANSACTION
| 特性 | SET autocommit=0 | START TRANSACTION |
| 本質 | 改變**提交模式**(會話級) | **顯式開啟**一個新事務 |
| 隱性提交前一事務 | **否** | **是**(隱性 COMMIT 前一事務) |
| 下一條語句自動開啟事務 | 是 | 否(需再次 START) |
| 適用場景 | 整個會話預設用手動事務 | 單一業務邊界明確控制 |
驅動程式層面的大坑:Python MySQLdb / PyMySQL 預設 autocommit=OFF
import MySQLdb
conn = MySQLdb.connect(host='...', user='...', passwd='...', db='...')
# 此時 conn.autocommit(False) 為預設行為!
cursor = conn.cursor()
cursor.execute("UPDATE account SET balance=balance-500 WHERE id=1")
cursor.execute("UPDATE account SET balance=balance+500 WHERE id=2")
# 若這裡拋出異常或忘記 commit,資料不會寫入!
conn.commit() # 必須顯式提交
conn.close()
正確做法
- 連線建立後立即
conn.autocommit(True) 回歸預設行為。
- 需要事務時:
cursor.execute("START TRANSACTION") → 多條 DML → conn.commit() / conn.rollback()。
- 或使用
with conn.cursor() as cur: 上下文管理器(PyMySQL 支援)。
Java / JDBC 驅動程式行為
- JDBC 標準規定
Connection.setAutoCommit(true) 為預設。
- 連線池(HikariCP/Druid)通常**不會改變**此預設值。
- Spring
@Transactional 底層呼叫 setAutoCommit(false) 開啟事務,提交/回滾後恢復 true。
儲存引擎限制:MyISAM 不支援事務
- MyISAM 表上執行
SET autocommit=0、**不會報錯**,但 COMMIT/ROLLBACK **無任何效果**,每條 DML 實際上仍自動提交。
- 需事務請務必使用 InnoDB(或 XtraDB、RocksDB 等支援事務引擎)。
- 檢查表引擎:
SHOW TABLE STATUS LIKE 'tbl_name'\G → Engine: InnoDB。
實戰範例:轉帳業務
-- 會話層面關閉自動提交
SET autocommit = 0;
-- 業務邏輯
SELECT balance FROM account WHERE id = 1 FOR UPDATE; -- 鎖定檢查餘額
UPDATE account SET balance = balance - 500 WHERE id = 1;
UPDATE account SET balance = balance + 500 WHERE id = 2;
-- 全部成功
COMMIT;
-- 任一失敗
ROLLBACK;
總結建議
- **應用層統一控制事務邊界**(Spring @Transactional、Python context manager),**勿依賴資料庫層面的 autocommit 切換**。
- 連線池配置保持
autocommit=true(預設),由業務代碼決定何時 START TRANSACTION。
- 若發現「資料更新了但查不到」或「明明回滾了卻生效」,優先檢查驅動程式
autocommit 設定與引擎是否為 InnoDB。