
很多開發者學習MySQL事務的時候只停留在理論層面不知道事務真正生效是什么樣子。本文提供兩套對照可運行代碼無事務產生臟數據、開啟事務異常自動回滾。直接運行代碼觀察數據庫數據變化直觀驗證事務效果。環境準備安裝依賴pipinstallpymysql測試表SQL必須使用InnoDB引擎MyISAM不支持事務。CREATETABLEaccount(idINTPRIMARYKEYAUTO_INCREMENT,usernameVARCHAR(32)NOTNULL,balanceDECIMAL(12,2)NOTNULLDEFAULT0)ENGINEInnoDBDEFAULTCHARSETutf8mb4;-- 初始化測試數據張三、李四各1000元INSERTINTOaccount(username,balance)VALUES(張三,1000.00),(李四,1000.00);業務場景張三轉賬200元給李四。流程張三余額扣減200模擬程序拋出異常李四余額增加200案例一不使用事務自動提交產生臟數據pymysql默認autocommitTrue每執行一條SQL就直接寫入數據庫。當中間代碼拋出異常后面SQL無法執行就會出現一部分成功、一部分失敗的數據錯亂。importpymysqldefdemo_without_transaction():# 默認 autocommitTrueconnpymysql.connect(host127.0.0.1,port3306,userroot,password你的密碼,databasetest_db,charsetutf8mb4)cursorconn.cursor()# 1.張三扣200這條SQL立刻生效落庫cursor.execute(UPDATE account SET balance balance - %s WHERE username%s,(200,張三))# 模擬業務異常、接口報錯、程序崩潰print(模擬程序發生異常)1/0# 2.李四加錢這行代碼永遠不會執行cursor.execute(UPDATE account SET balance balance %s WHERE username%s,(200,李四))cursor.close()conn.close()if__name____main__:demo_without_transaction()運行現象程序拋出ZeroDivisionError異常終止查詢數據庫張三余額變成800李四仍然1000出現臟數據錢憑空消失業務邏輯被破壞??復現完成后記得重置表數據方便測試下一個案例。UPDATEaccountSETbalance1000.00;案例二開啟事務異常自動回滾關鍵點設置conn.autocommit False關閉自動提交所有修改操作先在事務緩沖區不會真正寫入數據庫正常執行完畢調用conn.commit()持久化數據捕獲異常調用conn.rollback()撤銷全部修改importpymysqldefdemo_with_transaction():connpymysql.connect(host127.0.0.1,port3306,userroot,password你的密碼,databasetest_db,charsetutf8mb4)# 關閉自動提交開啟事務模式conn.autocommitFalsecursorconn.cursor()try:# 第一步張三扣款cursor.execute(UPDATE account SET balance balance - %s WHERE username%s,(200,張三))# 模擬異常觸發回滾邏輯print(模擬程序發生異常)1/0# 第二步李四收款cursor.execute(UPDATE account SET balance balance %s WHERE username%s,(200,李四))# 全部執行成功提交事務數據真正寫入數據庫conn.commit()print(?事務提交成功轉賬完成)exceptExceptionase:# 出現任何異常回滾本次事務所有變更conn.rollback()print(f?捕獲異常事務已全部回滾異常信息{e})finally:cursor.close()conn.close()if__name____main__:demo_with_transaction()運行現象異常分支程序拋出除零異常進入except代碼塊執行rollback()查詢數據庫張三、李四余額依舊都是1000數據完全沒有變化所有update操作全部撤銷不會產生臟數據測試正常提交場景把代碼中的1 / 0注釋掉再次運行。不會觸發異常執行commit()數據庫張三800李四1200轉賬業務正常完成。案例三演示部分回滾SAVEPOINT保存點MySQL支持保存點可以實現事務內部局部回滾不需要全部回滾。importpymysqldefdemo_savepoint():connpymysql.connect(host127.0.0.1,port3306,userroot,password你的密碼,databasetest_db,autocommitFalse,charsetutf8mb4)curconn.cursor()try:cur.execute(UPDATE account SET balancebalance-100 WHERE username張三)# 設置保存點sp1cur.execute(SAVEPOINT sp1)cur.execute(UPDATE account SET balancebalance100 WHERE username李四)# 回滾到保存點撤銷上面李四加錢操作張三扣錢保留cur.execute(ROLLBACK TO SAVEPOINT sp1)conn.commit()print(保存點演示完成)exceptExceptionase:conn.rollback()print(f異常回滾{e})finally:cur.close()conn.close()對比總結表場景無事務 autocommitTrue開啟事務 autocommitFalse程序中途報錯部分SQL生效生成臟數據全部操作回滾數據不變程序正常結束逐條SQL立即生效commit之后統一生效開發避坑要點autocommitFalse是開啟事務的前提忘記關閉自動提交commit/rollback完全無效。同一個事務內所有SQL必須使用同一個connection對象更換連接代表全新事務。異常分支必須手動執行rollback()否則未提交事務會掛起占用數據庫鎖資源。表引擎必須是InnoDBMyISAM不支持事務。盡量縮小事務粒度避免長事務長事務會造成鎖等待、數據庫性能下降。SELECT查詢語句不會修改數據不會產生事務變更SELECT ... FOR UPDATE會增加行鎖。業務模板訂單、庫存、轉賬等多寫業務直接套用這套模板conn.autocommitFalsetry:# 多條寫sqlconn.commit()exceptException:conn.rollback()finally:conn.close()通過以上樣例代碼就可以直觀驗證MySQL事務原子性效果一組操作要么全部成功要么全部撤銷。