自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL事務與隔離級別:解析臟讀、不可重復讀和幻讀問題

數據庫 MySQL
事務:是一組操作的集合,它是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統(tǒng)提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。

今日目標

  • 理解事務特性
  • 理解事務隔離級別
  • 理解不同事務下出現的問題臟讀、不可重復讀和幻讀

MySQL是廣泛使用的關系型數據庫管理系統(tǒng),它支持事務處理,確保數據操作的一致性和可靠性。本文將介紹MySQL事務的基本概念和重要性。

1. 事務簡介

事務:是一組操作的集合,它是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統(tǒng)提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。

我們現在就拿一個經典的銀行存取錢例子來說明: 李四給王五轉賬500塊錢,李四銀行賬戶就要減少500,并且王五賬戶要增加500。這一組操作就必須在一個事務范圍內,要么轉賬同時成功,要么轉賬同時失敗

id

name

money

1

李四

2000

2

王五

2000

轉賬分為以下情況:

1.正常情況:轉賬成功,可以分為以下基本三步完成,完成之后李四減少500,王五增加500,轉賬成功:

圖片圖片

最終數據庫結果:

id

name

money

1

李四

1500

2

王五

2500

2.異常情況:轉賬失敗,耶斯分為三步完成,假設李四減少500塊錢以后,王五賬戶金額沒有發(fā)生變化,這就造成了嚴重的數據不一致問題。

圖片圖片

問題解決方式:通過事務完成,我們在執(zhí)行業(yè)務邏輯之前開啟事務,業(yè)務執(zhí)行完畢后,關閉事務。如果執(zhí)行過程中出錯,則事務回滾,將數據恢復到事務開啟之前狀態(tài)。

圖片圖片

注意: 默認MySQL的事務是自動提交的,也就是說,當執(zhí)行完一條DML語句時,MySQL會立即隱 式的提交事務。

如果您覺得本文不錯,歡迎關注,點贊,收藏支持,您的關注是我堅持的動力!

2. 事務操作

通過sql語句,實現剛才的例子。

2.1. 數據準備

-- 創(chuàng)建數據庫test
create database  if not exists test;
use test;

-- 刪除表
drop table if exists tb_account;

create table tb_account(
                           id int primary key AUTO_INCREMENT comment 'ID',
                           name varchar(10) comment '姓名',
                           money double(10,2) comment '余額'
) comment '賬戶表';
insert into tb_account(name, money) VALUES ('李四',2000), ('王五',2000);

2.2. 正常轉賬情況

-- 正常轉賬情況

-- 1. 查詢李四余額
select * from tb_account where name = '李四';
-- 2. 李四的余額減少500
update tb_account set money = money - 500 where name = '李四';
-- 3. 王五的余額增加500
update tb_account set money = money + 500 where name = '王五';

-- 4. 查看賬戶結果
select * from tb_account;

測試完畢之后檢查數據的狀態(tài), 可以看到數據操作前后是一致的。

圖片圖片

2.3. 正常異常情況

-- 轉賬異常情況
-- 1. 查詢李四余額
select * from tb_account where name = '李四';
-- 2. 李四的余額減少500
update tb_account set money = money - 500 where name = '李四';
 出錯了....
-- 3. 王五的余額增加500
update tb_account set money = money + 500 where name = '王五';
-- 4. 查看賬戶結果
select * from tb_account;

我們把數據都恢復到2000, 然后再次一次性執(zhí)行上述的SQL語句(出錯了.... 這句話不符合SQL語 法,執(zhí)行就會報錯),檢查最終的數據情況, 發(fā)現數據在操作前后不一致了。

圖片圖片

2.3. 控制事務解決轉賬情況

1.開啟事務

-- 1.開啟事務
start transaction  或者 BEGIN;

2.提交事務

-- 2.提交事務
commit;

3.事務回滾

-- 3.事務回滾
rollback ;

轉賬案例

-- 開啟事務
start transaction;
-- 1. 查詢李四余額
select * from tb_account where name = '李四';
-- 2. 李四的余額減少1000
update tb_account set money = money - 500 where name = '李四';
-- 如果轉賬失敗 執(zhí)行rollback
-- 3. 王五的余額增加1000
update tb_account set money = money + 500 where name = '王五';
-- 如果正常執(zhí)行完畢, 則提交事務
commit;
-- 如果執(zhí)行過程中報錯, 則回滾事務
-- rollback;

3. 事務四大特性

MySQL事務遵循ACID屬性,即原子性、一致性、隔離性和持久性。

  • 原子性(Atomicity):事務是不可分割的最小操作單元,事務內的所有操作要么全部成功,要么全部失敗。如果出現錯誤,所有更改都會被撤銷,數據庫保持一致狀態(tài)。
  • 一致性(Consistency):事務執(zhí)行后,數據庫狀態(tài)必須滿足預定義的一致性狀態(tài),不會導致矛盾或不一致的數據。
  • 隔離性(Isolation):隔離性控制多個事務之間的相互影響。MySQL支持不同的隔離級別,以滿足不同應用的需求。
  • 持久性(Durability):事務一旦提交或回滾,它對數據庫中的數據的改變就是永久的,即使發(fā)生系統(tǒng)故障也不會丟失。

4. 事務隔離級別

SQL 標準中定義了四種隔離級別,分別是:

  • 讀未提交(Read Uncommitted):這是最低的隔離級別。在該級別下,一個事務可以讀取另一個事務尚未提交的數據,可能導致臟讀(讀取到未提交數據)、不可重復讀(同一查詢多次執(zhí)行結果不一致)和幻讀(查詢結果集發(fā)生變化) 等問題。這個級別的并發(fā)性最高,但數據完整性較差。
  • 讀已提交(Read Committed):在該級別下,事務只能讀取已提交的數據,避免了臟讀,但仍可能遇到不可重復讀和幻讀。這是許多數據庫系統(tǒng)的默認隔離級別,提供了更好的數據一致性。
  • 可重復讀(Repeatable Read):這是MySQL的默認隔離級別。在該級別下,事務在整個事務期間看到的數據保持一致,防止了臟讀和不可重復讀。但仍可能發(fā)生幻讀問題。
  • 串行化(Serializable):這是最高的隔離級別,也是最嚴格的。在該級別下,事務被強制排隊執(zhí)行,以避免任何并發(fā)問題,包括臟讀、不可重復讀和幻讀。這提供了最高級別的數據一致性,但也可能降低并發(fā)性能。

5. 事務隔離級別產生并發(fā)事務問題

事務隔離級別,是為了解決多個并行事務競爭導致的數據安全問題的一種規(guī)范。具體來說,多個事務競爭可能會產生三種不同的現象。

  • 臟讀。
  • 不可重復讀
  • 幻讀接下來我們分別介紹一下:

5.1. 臟讀(Dirty Read)

臟讀:一個事務讀到另外一個事務還沒有提交的數據

圖片圖片

示例sql:

1.事務A 中SQL

-- 步驟一:設置事務A隔離級別 讀未提交

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
use test;
-- 步驟三:開啟事務A,查詢ID=1的數據
start transaction;
select * from tb_account where id=1;

-- 步驟五:開啟事務A,查詢ID=1的數據
select * from tb_account where id=1;

commit ;

2.事務B中SQL

-- 步驟二:設置事務B隔離級別 讀未提交

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
use test;
-- 步驟四:開啟事務A,
start transaction;
-- 更新ID=1的數據   mnotallow=money-500
update tb_account set mnotallow=money-500  where id=1;


commit ;

示例結果:

圖片圖片

5.2. 不可重復讀(Non-Repeatable Read)

不可重復讀:一個事務先后讀取同一條記錄,但兩次讀取的數據不同,稱之為不可重復讀

圖片圖片

示例sql:

1.事務A 中SQL

-- 讀已提交隔離級別下 不可重復讀
-- 步驟一:設置事務A隔離級別 讀已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
use test;
-- 步驟三:開啟事務A,查詢ID=1的數據
start transaction;
select * from tb_account where id=1;

-- 步驟六:事務A,查詢ID=1的數據
select * from tb_account where id=1;


-- 步驟八:事務A,查詢ID=1的數據
select * from tb_account where id=1;
commit ;

2.事務B中SQL

-- 讀已提交隔離級別下 不可重復讀
-- 步驟二:設置事務B隔離級別 讀已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
use test;
-- 步驟四:開啟事務B,更新ID=1的數據   mnotallow=money-500
start transaction;
update tb_account set mnotallow=money-500  where id=1;
-- 步驟五:事務B查詢id=1數據
select * from tb_account where id=1;
-- 步驟七:事務B 提交事務 并查詢結果
commit ;
select * from tb_account where id=1;

示例結果

圖片圖片

5.3. 幻讀(Phantom Read)

幻讀:一個事務按照條件查詢數據時,沒有對應的數據行,但是在插入數據時,又發(fā)現這行數據 已經存在,好像出現了 "幻影"。

圖片圖片

示例sql:

1.事務A 中SQL

-- 可重復讀隔離級別下 幻讀
-- 步驟一:設置事務A隔離級別 可重復讀
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
use test;
-- 步驟三:開啟事務A,查詢ID>1的數據
start transaction;
select * from tb_account where id>1;

-- 步驟五:事務A,查詢ID>1的數據
select * from tb_account where id>1;


-- 步驟七:事務A,查詢ID>1的數據
select * from tb_account where id>1;
commit ;

2.事務B中SQL

-- 可重復讀隔離級別下 幻讀
-- 步驟二:設置事務B隔離級別 可重復讀
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
use test;
-- 步驟四:開啟事務B,插入一條數據
start transaction;
insert into tb_account values(3,'張三',2000);
-- 步驟六:提交事務B
commit ;

示例結果

圖片圖片

總結

隔離級別

臟讀

不可重復讀

幻讀

讀未提交(Read Uncommitted)

?

?

?

讀已提交(Read Committed)

?

?

?

可重復讀(Repeatable Read)

?

?

?

串行化(Serializable)

?

?

?

查看事務隔離級別

SELECT @@TRANSACTION_ISOLATION;

設置事務隔離級別

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
  • SESSION:表示當前客戶端會話窗口有效
  • GLOBAL: 表示對所有客戶端會話窗口有效

注意:事務隔離級別越高,數據越安全,但是性能越低。

責任編輯:武曉燕 來源: springboot葵花寶典
相關推薦

2024-04-19 08:18:47

MySQLSQL隔離

2022-06-29 11:01:05

MySQL事務隔離級別

2022-04-27 07:32:02

臟讀幻讀不可重復讀

2023-02-02 07:06:10

2024-04-24 08:26:35

事務數據InnoDB

2019-03-21 09:06:00

數據庫復讀幻讀

2022-01-03 07:18:05

臟讀幻讀 MySQL

2024-05-13 11:46:33

MySQL數據庫

2023-10-26 00:41:46

臟讀數據幻讀

2025-02-26 10:40:44

數據庫并發(fā)幻讀

2018-01-03 09:02:13

不可重復讀幻讀MySQL

2024-07-16 08:19:46

MySQL數據InnoDB

2021-08-02 09:01:05

MySQL 多版本并發(fā)數據庫

2023-12-26 08:08:02

Spring事務MySQL

2019-12-24 14:50:01

MySQL可重復讀數據庫

2024-03-11 00:00:00

mysqlInnoDB幻讀

2019-05-28 13:50:27

MySQL幻讀數據庫

2021-09-07 10:33:42

MySQL事務隔離性

2021-04-20 19:21:50

臟讀MySQL幻讀

2022-09-21 09:00:10

MySQL幻讀隔離級別
點贊
收藏

51CTO技術棧公眾號