事務學習筆記
阿新 • • 發佈:2017-09-14
ron nlog 失敗 art rom lsp 自動提交 隱患 into 事務是一組訪問並可能更新數據庫內容的SQL組成的執行單元,是數據庫並發控制和事務回滾的基本單位。
一個事務可能包含多個SQL,要麽都失敗,要麽都成功。
事務具備4個基本屬性
Atomic,同一個事務裏,要麽都提交,要麽都回滾。
Consistency,即在事務開始之前和事務結束之後,數據庫的完整性約束沒有被破壞。
Isolation,並發事務間的數據時彼此隔離的。
Durablliy,事務提交後,所有的結果務必被持久化。
支持事務的引擎:InnoDB、NDBCluster、TokuDB。
my.cnf配置 [mysqld]分段中,加入一行 transaction-isolation="READ-COMMITTED" #默認值是REPEATABLE-READ 在線(全局)修改 SET [GLOBAL] TRANSACTION ISOLATION LEVEL READ COMMITTED 查看事務隔離級別 select @@tx_isolation; 或者 show variables like ‘%iso%‘; 查看當前隔離級別 SELECT @@GLOBAL.TX_ISOLATION,@@SESSION.TX_ISOLATION; 例子: create table t1( c1 int(11) not null, c2 int(11) default null, c3 int(11) default null, primary key(c1), key c2(c2) ) +------+-------------+ | c1 | c2 | c3 | +------+-------------+ | 0 | 0 | 0 | | 1 | 1 | 1 | | 2 | 2 | 2 | | 3 | 3 | 3 | +------+------+------+
InnoDB如何解決幻讀的
1.RR級別下解決了幻讀問題。
2.引入gap lock,把兩條記錄中間的gap鎖住,避免其他事務寫入。
3.存在幻讀的條件:(1)<=RC級別。(2)或RR+ innodb_locks_unsafe_for_binlog=1
不支持事務的引擎:MyISAM、MEMORY/HEAP
查看某個引擎是否支持事務:show engines\G;
顯示開啟事務: START TRANSACTION [READ WRITE] -- 默認 [WITH CONSISTENT SNAPSHOT] --發起一個一致性快照讀,當前時刻提交的數據,都應該備份出來,從此刻起到之後的數據都不應該看得到。 [READ ONLYO] 或者BEGIN 開啟/關閉自動提交 set autocommit | @@autocimmit =0|1
提交事務:
顯式提交:commit
隱試提交:
BEGIN
START TRANSACTION
SET AUTOCOMMIT=1 / 其他非事務語句(DDL/DCL)。
回滾事務 顯示回滾:ROLLBACK。 隱式回滾:連接端口/超時。 autocommit=0 必要嗎? 好處:多語句提交時,不會每個SQL單獨提交,提高TPS 麻煩:有個事務忘記提交,鎖一直未釋放;另一個事務長期鎖等待,嚴重影響TPS。 如果沒有事務控制的話,那麽並發讀寫數據庫會有什麽隱患? 臟讀:一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務更新後達到了滿足其查詢條件的舊數據(此時它還未被提交),這種現象就稱為“臟讀”。 不可重復讀:一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務更新後達到了滿足其查詢條件的舊數據(此時它已被提交),這種現象就稱為“不可重復讀”。 幻讀:一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據(此時它已被提交),這種現象就被稱為“幻讀”。 事務隔離級別 Read Uncommitted(讀未提交)隔離級別最低 允許臟讀,允許事務查看其它事務所進行的未提交更改。 Read Commited(讀已提交) 允許幻讀,允許事務查看其它事務所進行的已提交更改。 Repeatable Read(可重復讀) 消除了臟讀、不可重復讀、幻讀,保證事務一致性。 確保每個事務的讀取結構都是一樣的,默認隔離級別。 Serializable(串行)隔離級別最高 串行化讀,每次讀都需要獲得表級共享鎖,讀寫間相互都會阻塞。 相當於MyISAM引擎,不支持並發了。
隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
Read Uncommitted(讀未提交) | 可能 | 可能 | 可能 |
Read Commited(讀已提交) | 不可能 | 可能 | 可能 |
Repeatable read(可重復讀) | 不可能 | 不可能 | 不可能(InnoDB特定條件下可能) |
Serializable(串行) | 不可能 | 不可能 | 不可能 |
my.cnf配置 [mysqld]分段中,加入一行 transaction-isolation="READ-COMMITTED" #默認值是REPEATABLE-READ 在線(全局)修改 SET [GLOBAL] TRANSACTION ISOLATION LEVEL READ COMMITTED 查看事務隔離級別 select @@tx_isolation; 或者 show variables like ‘%iso%‘; 查看當前隔離級別 SELECT @@GLOBAL.TX_ISOLATION,@@SESSION.TX_ISOLATION; 例子: create table t1( c1 int(11) not null, c2 int(11) default null, c3 int(11) default null, primary key(c1), key c2(c2) ) +------+-------------+ | c1 | c2 | c3 | +------+-------------+ | 0 | 0 | 0 | | 1 | 1 | 1 | | 2 | 2 | 2 | | 3 | 3 | 3 | +------+------+------+
讀未提交,Read uncommitted,RU隔離級別 |
|
session1 | session2 |
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED | |
begin | begin |
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
update t1 set c3=30 where c2=2 | |
select * from t1 where c2=2 | 2 | 2 | 30 | 讀到了t1還未提交的數據 |
讀已提交,Read committed,RC隔離級別 | |
session1 | session2 |
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED | |
begin | begin |
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
update t1 set c3=30 where c2=2 | |
select * from t1 where c2=2 | 2 | 2 | 2 | t1未提交時,還是讀取到舊數據 |
|
select * from t1 where c2=2 for update 希望讀取到最新版本,被阻塞,需等待 |
|
commit | |
select * from t1 where c2=2 | 2 | 2 | 30 | t1提交後,讀取到新數據 |
RC下的幻讀 | |
session1 | session2 |
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED | |
begin | begin |
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
insert into t1select 4,2,2 | |
select * from t1 where c2=2 | 2 | 2 | 2 | t1未提交時,還是讀取到舊數據 |
|
select * from t1 where c2=2 for update 行鎖等待 |
|
commit | |
select * from t1 where c2=2 | 2 | 2 | 2 | | 4 | 2 | 2 | ==>幻讀 t1提交後,是否加了for update都可以讀取到新數據 |
可重復讀,Repeatable read,RR隔離級別 | |
session1 | session2 |
SET SESSION TRANSACTION ISOLATION LEVEL RPEATABLE READ | |
begin | begin |
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
update t1 set c3=30 where c2=2; commit; |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 for update | 2 | 2 | 30 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
RR隔離級別可以避免幻讀 | |
session1 | session2 |
SET SESSION TRANSACTION ISOLATION LEVEL RPEATABLE READ | |
begin | begin |
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
insert into t1select 4,2,2 ERROR 1250(HY000):Lock wait timeout exceeded;try restarting transaction 鎖住c2=2這個gap,不允許有新的寫入 |
串行,serializable | |
session1 | session2 |
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE | |
begin | begin |
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
select * from t1 where c2=2 | 2 | 2 | 2 | |
|
update t1 set c3=20 where c2=20 ERROR 1250(HY000):Lock wait timeout exceeded;try restarting transaction |
事務學習筆記