MySQL事務總結

什麼是事務

事務(Transaction)是訪問和更新數據庫的程序執行單元;事務中可能包含一個或多個 sql 語句,這些語句要麼都執行,要麼都不執行。

事務四大特性

  • 原子性:事務是原子性操做,要麼所有成功,要麼所有失敗
  • 一致性:多個事務對數據庫操做會保證數據一致性
  • 隔離性:併發時,事務之間互不影響
  • 持久性:事務提交以後對數據庫的影響是持久性的,不會由於數據庫宕機致使數據丟失

事務併發帶來的問題

髒讀

讀到其它事務爲提交的數據mysql

不可重複讀

同一個事務,select語句相同但讀到數據不一樣sql

幻讀

同一個事務,select語句項目但讀到數據行數不一樣
不可重複讀的重點是修改,幻讀的重點在於新增或者刪除。數據庫

隔離級別

讀未提交(READ-UNCOMMITTED)

一個事務中,能夠讀取到其餘事務未提交的變動併發

讀提交(READ-COMMITTED)

一個事務中,能夠讀取到其餘事務已經提交的變動性能

可重複讀(REPEATABLE-READ)

一個事務中,直到事務結束前,均可以反覆讀取到事務剛開始看到的數據,不會發生變化
mysql的默認隔離級別是RR
RR和RC的區別是在一個事務中RR隔離級別的讀到一張表的數據都是同樣學習

可串行化(SERIALIZABLE)

即使每次讀都須要得到表級共享鎖,每次寫都加表級排它鎖,兩個會話間讀寫會相互阻塞,會致使MySQL性能下降。spa

查看隔離級別:線程

SELECT @@tx_isolation;

clipboard.png

原理

事務ACID特性是如何實現的哪?日誌

事務的原子性、隔離性、持久性都是爲了實現數據一致性

undo_log實現原子性

InnoDB實現事務的回滾靠的就是undo_log
對數據進行修改會追加undo_log

redo_log實現持久性

對數據庫的修改並不會當即修改磁盤中的數據表,而是先追加redo_log,再更新內存中數據(Write-ahead
logging,預寫式日誌),後續由master thread或者刷髒線程階段性將這些數據刷到磁盤
這樣階段性的刷髒能夠將多個IO merge成一個IO,也下降了訪問延時,提供系統吞吐,當MySQL忽然宕機也不會致使數據丟失,可根據redo_log進行數據恢復

鎖+MVCC實現隔離性

嚴格的隔離性對應Serializable(可串性化)隔離級別,在實際使用處於性能的考慮不多使用。
隔離性追求的是併發狀況下事務之間互補影響
  • (一個事務)寫操做與寫操做(另外一個事務)之間隔離經過鎖機制實現
  • (一個事務)寫操做與讀操做(另外一個事務)之間隔離經過MVCC實現

鎖機制

在對數據進行修改時,須要得到鎖,在數據修改爲功事務提交以後釋放鎖
MySQL有行鎖和表鎖,InnoDB使用的行鎖,行鎖比表鎖鎖定更少的資源,在大部分狀況的性能更高
模擬併發更新致使死鎖的狀況:
在一個窗口鏈接mysql並執行如下操做code

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update tuser set age=20 where id_card=4;
Query OK, 0 rows affected (0.12 sec)
Rows matched: 0  Changed: 0  Warnings: 0

另外一個窗口鏈接mysql並執行

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update tuser set age=20 where id_card=4;

查看鎖狀況

mysql> select * from information_schema.innodb_locks;
+-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
| lock_id         | lock_trx_id | lock_mode | lock_type | lock_table     | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
| 2150479:671:3:2 | 2150479     | X         | RECORD    | `test`.`tuser` | PRIMARY    |        671 |         3 |        2 | 1         |
| 2150478:671:3:2 | 2150478     | X         | RECORD    | `test`.`tuser` | PRIMARY    |        671 |         3 |        2 | 1         |
+-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.08 sec)
mysql> show engine innodb status;

clipboard.png

MVCC

Multi-Version Concurrency Control,即多版本的併發控制協議
MVCC解決了髒讀、不可重複讀、幻讀

MVCC,多個版本的數據能夠共存,主要是依靠數據的隱藏列(也能夠稱之爲標記位)和 undo log。
每行數據都會多2列
create_time系統版本號
delete_time系統版本號

select

1.判斷create_time, 行的系統版本號 <= 當前事務的系統版本號
2.判斷delete_time, 行的刪除版本未定義 || 大於當前事務版本號

update

插入一條新紀錄,更新create_time
刪除一條數據,並更新delete_time

insert

更新create_time

delete

更新delete_time

clipboard.png
1.事務A執行begin開啓事務,select查詢時向系統申請一個版本號
2.事務B執行update更新了tuser表中id=4這一行數據的版本號
3.事務A select查詢使用的仍是第一次select時使用的版本號,判斷id=4這一行的版本號比當前版本號大,經過undo_log找到和當前版本號一致的數據,事務A二次查詢結果時一致的,實現了事務的可重複讀

總結

MySQL做爲一個開源數據庫,被不少公司使用,在使用過程當中去深刻了解其內部原理是頗有必要的事情,知其然並知其因此然,學習是一個積累的過程,只要堅持就會有收穫。

參考

http://www.sohu.com/a/2925068...

相關文章
相關標籤/搜索