許多開發者誤以為:「事務中任一語句失敗,數據庫自動回滾所有操作」。實際上 MySQL 不會自動回滾,必須顯式 ROLLBACK 或在應用層捕獲異常後回滾。
CREATE TABLE test_tab (
f1 INT PRIMARY KEY,
f2 VARCHAR(11)
) ENGINE=InnoDB;
START TRANSACTION;
INSERT INTO test_tab VALUES (1, '2'); -- 成功
INSERT INTO test_tab VALUES (1, '3'); -- 主鍵衝突報錯 1062
COMMIT; -- 未執行
結果:第一條 INSERT 已執行但未提交,若後續同連接執行任何 COMMIT/START TRANSACTION(隱式提交),第一條數據會被持久化!
COMMITROLLBACK 撤銷所有bool m_flag = true;
void execute(MYSQL* conn, string sql) {
if (mysql_real_query(conn, sql.c_str(), sql.length()))
m_flag = false; // 標記失敗
}
bool commit_transaction() {
if (!m_flag) {
mysql_rollback(conn); // 失敗回滾
return false;
}
return mysql_commit(conn) == 0; // 全部成功提交
}
CREATE PROCEDURE sp_transfer()
BEGIN
DECLARE t_error INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error = 1;
START TRANSACTION;
INSERT INTO test_tab VALUES (1, '2');
INSERT INTO test_tab VALUES (1, '3'); -- 失敗觸發 handler
IF t_error = 1 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END;
CALL sp_transfer();
優勢:邏輯封裝在數據庫層,應用只需調用 CALL,無感知 SQL 細節,異常自動轉 ROLLBACK。
START TRANSACTION 會隱式提交前一個未完成事務CREATE/DROP/ALTER)會隱式提交ROLLBACK@Transactional)