mysql四种输入_mysql四种事务隔离级别
mysql事務并發問題
ACID什么的就不啰嗦了。mysql多個事務并發的時候,可能會出現如下問題:
1. 更新丟失
即兩個事務同時更新某一條數據,后執行的更新操作會覆蓋先執行的更新操作,導致先執行的更新結果丟失。
2. 臟讀
即一個事務會讀到另一個事務尚未提交的數據更新,由于該數據更新可能會回滾,所以稱之為臟讀。
3. 不可重復讀
即一個事務中對同一行數據讀取兩次,會得到不同的結果。原因是在該事務兩次讀取之間,其他事務會修改此數據。
4. 幻讀
即一個事務對同一個表執行兩次查詢,會得到相同的結果行數。即使在該事務兩次查詢之間,其他事務同時也向此表插入了新的數據。
mysql事務隔離級別
mysql共支持四種事務隔離級別,分別是:
read uncommitted(讀取未提交數據):從字面上理解,該事務隔離級別允許讀取未提交數據。僅處理更新丟失的問題,但是不處理臟讀、不可重復讀、幻讀的問題。
read committed(讀取已提交數據):從字面上理解,該事務隔離級別允許讀取已經提交的數據,即未提交的數據不可讀取。則該事務隔離級別處理更新丟失、臟讀的問題,不處理不可重復讀、幻讀的問題。
repeatable read(重復讀):該事務隔離級別無法從字面上理解了,處理更新丟失、臟讀、不可重復讀的問題,不處理幻讀的問題。
serializable(最高隔離級別):該事務隔離級別為最高事務隔離級別,處理以上所有問題,包括:更新丟失、臟讀、不可重復讀、幻讀。
以上四種事務隔離級別依次遞增,事務隔離級別越高,一致性越強可用性越差。
可以看到,所有的事務隔離界別都會處理更新丟失的問題。mysql默認的事務隔離級別為:repeatable read,即默認不處理幻讀的問題。
廢話不多說,直接上例子(大前提:數據庫引擎為innoDB):
1. 首先要注意:mysql自動提交事務要關閉
查看mysql的autoCommit是否開啟:
--查看mysql是否自動提交事務
show variables like 'autocommit';
如果需要關閉autoCommit,則執行如下語句:
--關閉autoCommit
set autocommit = 0;
2. 查看、設定mysql的事務隔離級別:注意只在當前會話session有效。
--查看當前數據庫事務隔離級別
select @@tx_isolation;--設定當前數據庫隔離級別為 read uncommitted
set session transaction isolation level read uncommitted;---set session transaction isolation level read committed ;--set session transaction isolation level repeatable read ;--set session transaction isolation level serializable;
3.?創建測試表及測試數據
usetest;create tabledt_table1 (
idint auto_increment primary key,
valuevarchar(50) null);insert into dt_table1 (value) value ('00000000');insert into dt_table1 (value) value ('00000000');insert into dt_table1 (value) value ('00000000');
(1)測試更新丟失
我們先更新一下數據,以便后續測試。
update dt_table1 set value = '00000000' where id = 1;
設定測試環境:創建兩個session連接,并設定事務隔離級別 read uncommited
set session transaction isolation level read uncommitted;
打開session連接1,執行如下腳本,通過第三步可以看到數據已經被更新:
start transaction; --第一步
update dt_table1 set value = 'update 1' where id = 1; --第二步
select * from dt_table1 where id = 1; --第三步
打開session連接2,執行如下腳本,當執行第五步的時候,可以看到該更新操作被阻塞了。
start transaction; --第四步
update dt_table1 set value = 'update 2' where id = 1; --第五步
回到session連接1,執行commit,可以看到session連接2中第五步的更新操作也取消了阻塞并執行通過了。
commit; --第六步
回到session連接2,執行查詢并commit。最終數據被更新為值‘update 2’。
select * from dt_table1 where id = 1; --第七步
commit; --第八步
通過以上的例子,我們可以看出,即使是mysql的最低事務隔離級別,也解決了更新丟失的問題。即:在session連接1中執行更新操作但尚未提交事務,session連接2中的更新操作會被阻塞,以避免session連接1中的更新丟失。將兩個session連接的事務隔離級別設定為其他等級也會得到同樣的結果。
(2)測試臟讀
我們先更新一下數據,以便后續測試。
update dt_table1 set value = '00000000' where id = 1;
設定測試環境:創建兩個session連接,并設定事務隔離級別 read uncommited。在此事務隔離級別下,會出現臟讀的問題。
set session transaction isolation level read uncommitted;
打開session連接1,執行如下腳本。
start transaction; --第一步
update dt_table1 set value = 'read uncommitted' where id = 1; --第二步
打開session連接2,執行如下腳本??梢钥吹阶x取到了session連接1中已經更新但尚未提交的數據(查詢值為‘read uncommited’)。
select * from dt_table1 where id = 1; --第三步
回到session連接1,執行rollback。
rollback; --第四步
回到session連接2,再次執行查詢,可以看到查詢值已經成功回滾(查詢值為:‘00000000’)
select * from dt_table1 where id = 1; --第五步
通過以上的例子,我們可以看出,將mysql的事務隔離級別設定為read uncommited,會出現臟讀的問題。即:session連接2中在第三步會讀取到session連接1中已經更新但尚未提交的數據,由于session鏈接1可能會發生事務回滾,那么session連接2中讀取到的數據也就無效了,即讀取臟數據,即臟讀。
如果設定事務隔離級別為read commited或以上,則不會出現此問題。上例中第三步讀取到的值會為:'00000000'。即不會臟讀。
(3)嘗試不可重復讀
我們先更新一下數據,以便后續測試。
update dt_table1 set value = '00000000' where id = 1;
設定測試環境:創建兩個session連接,并設定事務隔離級別 read commited。在此事務隔離級別下,會出現不可重復讀情況。
set session transaction isolation level read committed;
打開session連接1,執行如下腳本??梢钥吹讲樵冎禐椤?0000000’
start transaction; --第一步
select * from dt_table1 where id = 1; --第二步
打開session連接2,執行如下腳本。
start transaction; --第三步
update dt_table1 set value = 'read committed' where id = 1; --第四步
commit; --第五步
回到session連接1,執行如下腳本??梢钥吹讲樵冎禐椤畆ead commited’
select * from dt_table1 where id = 1; --第六步
commit; --第七步
通過以上的例子,我們可以看出,將mysql的事務隔離級別設定為read commited,會出現不可重復讀問題,即在session連接1中的一個事務中,先后兩次讀取到的值不一樣。原因是在該事務兩次讀取之間,session連接2的事務修改并提交了此數據。
如果設定事務隔離級別為repeatable read或以上,則不會出現此問題。上例中第六步讀取到的數據值依然為‘00000000’
(4)嘗試幻讀
設定測試環境:創建兩個session連接,并設定事務隔離級別 repeatable read。在此事務隔離級別下,會出現幻讀的情況。
set session transaction isolation level repeatable read ;
我們先更新一下數據,以便后續測試
update dt_table1 set value = '00000000' where 1=1;
打開session連接1,執行如下腳本。我們記錄下第二步查詢結果行數,假如為n行。
start transaction; --第一步
select * from dt_table1; --第二步
打開session連接2,執行如下腳本。
start transaction; --第三步
insert into dt_table1 (value) value ('phantom read new'); --第四步
commit; --第五步
回到session連接1,執行如下腳本,可以看到第六步查詢結果行數依然為n,但是執行第七步更新操作的時候,更新影響行數卻是n+1。執行第九步查詢的時候結果行數也是n+1
select * from dt_table1; --第六步
update dt_table1 set value = 'phantom read' where 1=1; --第七步
commit; --第八步
select * from dt_table1; --第九步
通過以上的例子,我們可以看出幻讀問題的存在,即:第六步查詢結果明明是n行,但是第七步跟新操作影響行數卻是n+1,難道是我的幻覺?這就是幻讀。
如果設定事務隔離級別為serializable,則不會出現此問題。第四步執行輸入插入操作時會被阻塞,第七步更新操作影響結果行數和第六步查詢結果行數也會保持一致,且執行到第九步的時候,可以看到第四步新插入的數據也并沒有被第七步更新掉。
總結
以上是生活随笔為你收集整理的mysql四种输入_mysql四种事务隔离级别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle mysql 字段_Orac
- 下一篇: sinacloud webpy mysq