事務(transaction)是資料庫併發控制的不可分割的基本單位,可以將一系列的資料庫操作集合到乙個事務中,從總體上來講這個事務可能會對資料庫進行一些變動。事務存在的意義在於多個同時事務執行完成以後不管成功與否都要保持資料的乾淨、有序,也就是資料的一致性。比如我們在 12306 上購買火車票,如果付款成功我們將獲得金錢 -1、火車票 +1,如果付款失敗則金錢 -0、火車票 +0 。所以你有沒有想過去找找免費購票的漏洞?
acid四大特性是事務的基本特性,其保證了上面的買票行為能正確執行。
事務要麼成功,要麼失敗,如果失敗則所有對資料庫的操作都沒有執行。如果在執行過程**現異常錯誤,則所有執行都取消,否則就會對資料庫產生***,造成資料「汙染」。mysql 原子性實現的基礎是 undo log。
1begin;
2insert into xx_table (id, name) values (1, 'a');
上述操作在事務開啟後,如果 commit 則應該更改資料記錄,如果失敗則可以通過 rollback 回滾到之前的狀態。
都事務成功執行,則所有對資料庫的修改都需要持久化的磁碟上,即使中途出現斷電、宕機、重啟等異常情況,否則就會出現資料不一致。mysql 永續性實現的基礎是 redo log。
1begin;
2insert into xx_table (id, name) values (1, 'a');
3commit;
上述事務成功執行後應該保證資料可以準確無誤的落入磁碟中,即使出現異常情況。
當多個事務同時執行時會出現互相爭奪同一資源,也可能同時修改同一資料,這就需要保證各個資料之間能合理的執行自身的操作,同時不影響另一事務執行,最後還要盡可能提高併發執行的效能。mysql 根據效能和併發安全性實現了4個隔離級別,級別越高併發執行能力越低,併發安全性越高:
mysql 的隔離性是通過鎖、多版本併發(mvcc)實現的。
保證資料的一致性正是資料庫最重要的部分,mysql 正是通過原子性、永續性和隔離性來保證了資料的一致性。
如何保證事務失敗情況下時間能倒流呢?乙個簡單的辦法就是拿個小本本把事務中每乙個操作記下來,如果出現異常就可以照著改回來就好了。mysql 的 undo log 就是這個小本本,當事務開啟後,mysql 會把相應的每乙個的操作記錄到記憶體中,再從記憶體持久化到硬碟中。而且undo log持久化到硬碟是在資料庫變更之前執行完成的,這樣即使中途出現斷電等情況,重啟後依然可以更加 undo log 就行回滾。
mysql undo log 有兩個特點:
undo log 保證了單個事務的原子性
當事務成功提交後需要保證資料變更能準確到落到磁碟中,假設這一過程中被拔了電源改怎麼辦?mysql 寫資料是先寫到記憶體快取區中 (buffer pool)中,然後由後台執行緒定期將資料由記憶體搬到磁碟中,所以一斷電記憶體中的資料就沒了。好記性不如爛筆頭,同樣乙個簡單的辦法就是拿出我們的小本本記下來,等重啟了就照著小本本重新執行一次就可以了,這就是 mysql 的 redo log。
redo log 從快取到磁碟這一過程是同步的,redo log 保證了事務的永續性。
類似於多執行緒中的鎖技術,mysql 中的鎖可以用來解決多個請求更改同一資料問題,這是一種常用的併發控制手段,鎖可以解決資料不一致問題,同時也降低了併發效能。mysql 有兩種鎖來控制併發操作:共享鎖和排他鎖
1、共享鎖 (share lock),讀鎖: 讀鎖可以共享,多個讀請求可以併發執行;
2、排他鎖 (exclusive lock),寫鎖:寫鎖會排斥其他所有獲取鎖的請求,一直阻塞至操作完成釋放鎖。
加讀鎖方法:
1select * from xx_table where id = 1 lock in share mode;
加寫鎖方法:
1select * from xx_table where id = 1 for update;
單純使用鎖來解決併發安全問題可能會發幅度降低效能,mysql 引入了另外一種機制,多版本併發控制(mvcc)。當某乙個事務連線到mysql後,它所查詢到的資料為當前時刻的快照,其他事務對同一資料的更改並不會影響到當前事務的查詢。也就是其他事務的變更操作在未提交之前對當前事務都是不可見的。
mysql 會在每一張表後面隱式的新增三列,其中兩列(db_trx_id,db_roll_pt)和 mvcc 有關,這兩列標註了此行資料變更或被刪除的事務id或時間戳。當事務變更、刪除某一資料時,mysql 並不會真正執行操作,只是在相應的列做好標記,表示資料已經被更改,其他事務讀到的仍是原來的老資料。
通過 mvcc 就可以解決讀操作不一致問題(髒讀),避免了鎖帶來的巨大開銷
mysql 實現了四個級別的事務隔離,開發者可以針對不同的場景選擇合適的事務隔離級別,已達到效能與安全之間的平衡。
讀未提交 read uncommitted:
在這一級別,當前事務可以讀取到其他事務未提交的資料,這樣做的壞處是髒讀,好處是不需要任何鎖,可以做到讀寫並行,大幅度提高併發效能。
讀已提交 readcommitted:
乙個未提交的事務對當前事務是不可見的,當前事務可以讀取到已經提交的變動,在實際開發中,大多數場景都使用此級別。mysql 的讀已提交使用排它鎖和 mvcc 實現,實現了讀寫分離,但是會產生不可重複讀和幻讀問題。
可重複讀 repeatable read:
這是 mysql 的預設隔離級別,單個事務內讀取的結果是不變的,解決了髒讀、不可重複讀問題,但是仍存在幻讀問題(mysql 通過 next-key lock 避免了幻讀),此級別可以使用讀寫鎖實現,也可以採用 mvcc 實現,採用讀寫鎖邏輯簡單但只能序列執行,採用寫鎖+ mvcc 實現複雜但可以讀寫分離。
序列讀 serializable:
嚴格採用讀寫鎖實現,所有操作全部序列執行,不會造成資料不一致問題,但併發效能極差。
mysql 正是通過原子性、永續性和隔離性,保證了資料的一致性。
mysql 多事務 MySQL多事務併發控制
mysql的預設隔離級別是可重複讀。若兩個事務a和b操作同一資源,a和b都通過begin開啟事務後,若a只存在讀操作,則b可以對資料進行寫操作,且b的寫操作不會影響a的讀,即a每次讀到的內容都是一致的 就算b已經提交 若a進行了寫操作,則b的讀操作不受影響,但b的寫操作會被阻塞,直到a提交了事務或者...
MySQL多事務併發控制
mysql的預設隔離級別是可重複讀。若兩個事務a和b操作同一資源,a和b都通過begin開啟事務後,若a只存在讀操作,則b可以對資料進行寫操作,且b的寫操作不會影響a的讀,即a每次讀到的內容都是一致的 就算b已經提交 若a進行了寫操作,則b的讀操作不受影響,但b的寫操作會被阻塞,直到a提交了事務或者...
mysql 併發控制及事務
實現的併發訪問的控制技術是基於鎖 鎖分為表級鎖和行級鎖,myisam儲存引擎不支援行級鎖 innodb支援表級鎖和行級鎖 鎖的分類有讀鎖和寫鎖,讀鎖也被稱為共享鎖,加讀鎖的時候其他的人可以讀 寫鎖也稱為獨佔鎖或排它鎖,乙個寫鎖會阻塞其他讀操作和寫操作 鎖還分為隱式鎖和顯式鎖,隱式鎖由儲存引擎自行管理...