mysql事物主要用於處理操作量大,復雜度高的數據。比如說,在人員管理系統中,你刪除一個人員,你既要刪除人員的基本資料,也要刪除和該人員相關的信息,如信箱,文章等。這樣,這些數據庫操作語句就構成一個事物。注意一下幾點:
- 在MySQL中只有使用了Innodb數據庫引擎的數據庫或表才支持事務。
- 事物處理可以用來維護數據庫的完整性,保證成批的sql語句要么全部執行,要么全部不執行。
- 事物用來管理insert,update,delete語句。
先簡單介紹一下事物吧。事物是DBMS的執行單位。它由有限的數據庫操作序列組成的,但不是任意的數據庫操作序列都能成為事物。一般來說,事物必須滿足4個條件(ACID):
原子性:組成事物處理的語句形成了一個邏輯單元,不能只執行其中一部分。換句話說,事物是不可分割的最小單元。比如銀行轉賬過程中,必須同時從一個賬戶減去轉賬金額,並加到另一個賬戶中,只改變一個賬戶是不合理的。
一致性:在事物處理執行前后,mysql數據庫是一致的。也就是說,事物應該正確的轉換系統狀態。比如銀行轉賬過程中,要么轉賬金額從一個賬戶到另一個賬戶,要么兩個賬戶都不變,沒有其他情況。
隔離性:一個事物處理對另外一個事物處理沒有影響。比如說銀行轉賬過程中,在轉賬事物沒有提交之前,另一個轉賬事物只能處於等待狀態 。
可靠性:事物處理的效果能夠被永久保存下來。反過來說,事物能夠承受所有的失敗。包括服務器,進程,通信以及媒體失敗等等。比如銀行轉賬過程中,轉賬后賬戶的狀態要能被保存下來。
mysql的事物處理主要有兩種方法:
1. begin,rollback,commit來實現
begin 開始一個事物
rollback 事物回滾
commit 事物確認,事物提交
2,直接用set來改變mysql的自動提交模式
mysql默認z是自動提交的,也就是你提交一個query,它就直接執行。
set autocommit = 0 禁止自動提交模式
set autocommit = 1 開啟自動提交模式
mysql中只用INNODB和BDB類型的數據表才能支持事物處理(切記)!
來看一個例子:
先假設一下問題的背景:網上購書,某書《mysql數據庫》編號為123,只剩最后一本,而這個時候兩個用戶幾乎同時對這本書發出了購書請求,讓我們來看看整個過程:
在具體分析之前,先來看看數據表的定義:

對於用戶甲來說,他的動作稍微比乙快一點點,其購買過程中所觸發的動作大致是這樣的:
1.select book_number from book where book_id = 123;
book_number 大於0,確認購買行為並更新book_number
2.update book set book_number = book_number—1 where book_id = 123;
購書成功
表面上看甲乙的操作都成功了,他們都買到了書,但是庫存只有一本,他們怎么可能都成功呢?再看看數據表里book_number的內容,已經變成“-1”了,這當然是不能允許的(實際上,聲明這樣的列類型應該加上unsigned的屬性,以保證其不能為負,這里是為了說明問題所以沒有這樣設置)
好了,問題陳述清楚了,再來看看怎么利用事務來解決這個問題,打開MySQL手冊,可以看到想用事務來保護你的SQL正確執行其實很簡單,基本就是三個語句:開始,提交,回滾。
開始:START TRANSACTION或BEGIN語句可以開始一項新的事務
提交:COMMIT可以提交當前事務,是變更成為永久變更
回滾:ROLLBACK可以回滾當前事務,取消其變更
此外,SET AUTOCOMMIT = {0 | 1}可以禁用或啟用默認的autocommit模式,用於當前連接。
那是不是只要用事務語句包一下我們的SQL語句就能保證正確了呢?比如下面代碼:
答案是否定了,這樣依然不能避免問題的發生,如果想避免這樣的情況,實際應該如下:

由於加入了FOR UPDATE,所以會在此條記錄上加上一個行鎖,如果此事務沒有完全結束,那么其他的事務在使用SELECT ... FOR UPDATE請求的時候就會處於等待狀態,直到上一個事務結束,它才能繼續,從而避免了問題的發生,需要注意的是,如果你其他的事務使用的是不帶FOR UPDATE的SELECT語句,將得不到這種保護。
