MySQL事務

原文連接http://zhhll.icu/2021/01/02/%E6%95%B0%E6%8D%AE%E5%BA%93/%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E4%BA%8B%E5%8A%A1/mysql

MySQL事務

事務:一個或一組SQL語句組成的一個執行單元,要麼所有成功,要麼所有失敗。sql

注:mysql中只有innodb支持事務數據庫

事務的ACID特性

  • 原子性(Atomicity) 指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生
  • 一致性(Consistency) 指事務必須使數據庫從一個一致性狀態變成另外一個一致性狀態
  • 隔離性(Isolation) 指一個事務的執行不能被另外一個事務干擾
  • 持久性(Durability) 指事務一旦被提交,對數據庫中數據的改變是永久性的

事務的建立

默認狀況下mysql的事務是自動提交的session

show variables like '%autocommit%';

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+

#須要手動的禁用一下事務自動提交
set autocommit = 0;
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+

事務的隔離級別

查看數據庫的隔離級別

#mysql8中查看隔離級別
select @@transaction_isolation;

+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+

#mysql8以前查看隔離級別
select @@tx_isolation;

修改數據庫的隔離級別

#修改全局隔離級別
set global transaction isolation level read committed;
#修改會話隔離級別
set session transaction isolation level read committed;

事務併發出現的問題

  • 髒讀 對於兩個事務T1,T2,T1讀取了已經被T2更新但尚未被提交的字段以後,若T2回滾,T1讀取到的內容就是臨時無效的
  • 不可重複讀 對於兩個事務T1,T2,T1讀取了一個字段,T2更新了該字段,以後T1再次讀取同一個字段,值就不一樣了(描述的是修改操做)
  • 幻讀 對於兩個事務T1,T2,T1從一個表中讀取了一個字段,而後T2在該表中插入了一些新的行,T1再次讀取同一個表,就會多出幾行(描述的是插入操做)

髒讀和幻讀類似,髒讀屬於修改操做,幻讀屬於插入操做併發

隔離級別

  • READ UNCOMMITED(讀未提交的數據) 容許事務讀取未被其餘事務提交的變動,髒讀、不可重複讀、幻讀問題都存在
  • READ COMMITED(讀已提交的數據) 只容許事務讀取已被其餘事務提交的數據,能夠避免髒讀,可是不可重複讀和幻讀仍存在
  • REPEATABLE READ(可重複讀) 確保事務能夠屢次從一個字段中讀取相同的值,在這個事務持續期間,禁止其餘事務對這個字段進行更新,能夠避免髒讀和不可重複讀,但幻讀仍存在(Mysql默認的事務隔離級別)
  • SERIALIZABLE(串行化) 確保事務能夠從一個表中讀取相同的行,在這個事務持續期間,禁止其餘事務對該表執行插入、更新和刪除操做,全部併發問題均可以免,可是性能低下

測試各個隔離級別

開啓兩個mysql鏈接,爲mysql1和mysql2性能

原始數據爲測試

select * from users;
 +----+---------+
| id | u_name  |
+----+---------+
|  2 | 張三    |
|  3 | 張三0   |
|  4 | 張三1   |
|  5 | 張三2   |
+----+---------+
測試READ UNCOMMITTED
#首先設置mysql1和mysql2隔離級別爲read uncommited
 set session transaction isolation level read uncommitted;
 #禁用mysql1 mysql2的自動提交
 set autocommit = 0;
 
 update users set u_name='李四' where id = 3;#①  mysql1修改數據但未提交
 select * from users where id =3;#② mysql1 查詢數據 爲李四
 select * from users where id =3;#③ mysql2 查詢數據 也爲李四 查詢到了mysql1中未提交的數據 出現了髒讀
 
insert into users (u_name) values ('劉亦菲');#④mysql1 插入數據但未提交
select * from users where u_name = '劉亦菲';#⑤mysql1 查詢到該數據
select * from users where u_name = '劉亦菲';#⑥mysql2 查詢到該數據  出現了幻讀

rollback;#⑦mysql1 回滾以前的操做  此時mysql2在查詢發現以前查詢到的數據都變了 出現了不可重複讀
測試read commited
#首先設置mysql1和mysql2隔離級別爲read commited
 set session transaction isolation level read committed;
 #禁用mysql1 mysql2的自動提交
 set autocommit = 0;
 
 update users set u_name='李四' where id = 3;#①  mysql1修改數據但未提交
 select * from users where id =3;#② mysql1 查詢數據 爲李四
 select * from users where id =3;#③ mysql2 查詢數據 爲張三0 沒有出現髒讀
 
insert into users (u_name) values ('劉亦菲');#④mysql1 插入數據但未提交
select * from users where u_name = '劉亦菲';#⑤mysql1 查詢到該數據
select * from users where u_name = '劉亦菲';#⑥mysql2 沒有查詢到該數據

commit;#⑦mysql1 提交以前的操做  此時mysql2在查詢發現以前查詢到的數據都變了 出現了不可重複讀
測試read commited
#首先設置mysql1和mysql2隔離級別爲read commited
 set session transaction isolation level read committed;
 #禁用mysql1 mysql2的自動提交
 set autocommit = 0;
 
 update users set u_name='李四' where id = 3;#①  mysql1修改數據但未提交
 select * from users where id =3;#② mysql1 查詢數據 爲李四
 select * from users where id =3;#③ mysql2 查詢數據 爲張三0 沒有出現髒讀
 
insert into users (u_name) values ('劉亦菲');#④mysql1 插入數據但未提交
select * from users where u_name = '劉亦菲';#⑤mysql1 查詢到該數據
select * from users where u_name = '劉亦菲';#⑥mysql2 沒有查詢到該數據

commit;#⑦mysql1 提交以前的操做  此時mysql2在查詢發現以前查詢到的數據都變了 出現了不可重複讀
測試repeatable read
#首先設置mysql1和mysql2隔離級別爲repeatable read
 set session transaction isolation level repeatable read;
 #禁用mysql1 mysql2的自動提交
 set autocommit = 0;
 
 update users set u_name='李四' where id = 3;#①  mysql1修改數據但未提交
 select * from users where id =3;#② mysql1 查詢數據 爲李四
 select * from users where id =3;#③ mysql2 查詢數據 爲張三0 沒有出現髒讀
 
insert into users (u_name) values ('劉亦菲');#④mysql1 插入數據但未提交
select * from users where u_name = '劉亦菲';#⑤mysql1 查詢到該數據
select * from users where u_name = '劉亦菲';#⑥mysql2 沒有查詢到該數據

commit;#⑦mysql1 提交以前的操做  此時mysql2仍是沒有數據

保存點savepoint

在一個事務中能夠設置保存點,和rollback搭配使用code

測試保存點

select * from users;

+------+-----------+
| id   | u_name    |
+------+-----------+
|    2 | 張三      |
|    3 | 李四      |
|    4 | 張三1     |
|    5 | 張三2     |
| 1006 | 劉亦菲    |
+------+-----------+

delete from users where id = 4;
savepoint a;#設置保存點
delete from users where id = 1006;
rollback to a;#回滾到保存點的位置


select * from users;

+------+-----------+
| id   | u_name    |
+------+-----------+
|    2 | 張三      |
|    3 | 李四      |
|    5 | 張三2     |
| 1006 | 劉亦菲    |
+------+-----------+

因爲自己的博客百度沒有收錄,博客地址http://zhhll.icu事務

相關文章
相關標籤/搜索