欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL 事務(wù)的概念及ACID屬性和使用詳解

 更新時間:2025年05月29日 11:26:02   作者:IsLand1314~  
MySQL通過多線程實現(xiàn)存儲工作,因此在并發(fā)訪問場景中,事務(wù)確保了數(shù)據(jù)操作的一致性和可靠性,下面通過本文給大家介紹MySQL 事務(wù)的概念及ACID屬性和使用詳解,感興趣的朋友一起看看吧

一、什么是事務(wù)

  • 定義:由一條或者多條 sql 語句構(gòu)成的 sql 集合體,這個集合體合在一起共同要完成某種任務(wù)。MySQL通過多線程實現(xiàn)存儲工作,因此在并發(fā)訪問場景中,事務(wù)確保了數(shù)據(jù)操作的一致性和可靠性。 事務(wù)還規(guī)定 不同的客戶端看到的數(shù)據(jù)是不相同的
    • 事務(wù)就是要做的或所做的事情,主要用于 處理操作量大,復(fù)雜度高的數(shù)據(jù)
    • 假設(shè)一種場景:你畢業(yè)了, 學(xué)校的教務(wù)系統(tǒng)后臺 MySQL 中,不在需要你的數(shù)據(jù),要刪除你的所有信息(一般不會:) ), 那么要刪除你的 基本信息(姓名,電話,籍貫等)的同時,也刪除和你有關(guān)的其他信息,比如:你的各科成績,你在校表 現(xiàn),甚至你在論壇發(fā)過的文章等。這樣,就需要多條 MySQL 語句構(gòu)成,那么所有這些操作合起來,就構(gòu)成了一個事務(wù)。
  • 背景:在沒有控制的情況下進(jìn)行 CURD 操作(創(chuàng)建、更新、讀取、刪除)可能導(dǎo)致數(shù)據(jù)不一致的問題。例如,在火車票售票系統(tǒng)中,兩個用戶同時嘗試購買最后一張票,可能造成同一張票被賣出兩次的現(xiàn)象

CURD滿足什么屬性,能解決上述問題?

  • 買票的過程得是原子的吧
  • 買票互相應(yīng)該不能影響吧
  • 買完票應(yīng)該要永久有效吧
  • 買前,和買后都要是確定的狀態(tài)吧

二、事務(wù)的屬性及使用

2.1 事務(wù)的 ACID 屬性

一個 MySQL 數(shù)據(jù)庫,可不止你一個事務(wù)在運行,同一時刻,甚至有大量的請求被包裝成 事務(wù),在向 MySQL 服務(wù)器發(fā)起事務(wù)處理請求。而每條事務(wù)至少一條 SQL ,最多很多 SQL ;這樣如果大 家都訪問同樣的表數(shù)據(jù),在不加保護(hù)的情況,就絕對會出現(xiàn)問題。甚至,因為事務(wù)由多條 SQL 構(gòu)成,那 么,也會存在執(zhí)行到一半出錯或者不想再執(zhí)行的情況,那么已經(jīng)執(zhí)行的怎么辦呢?

所有,一個完整的事務(wù),絕對不是簡單的 sql 集合,還需要滿足如下四個屬性:

  • 原子性(Atomicity,或稱不可分割性):事務(wù)的所有操作要么全部完成,要么完全不執(zhí)行,任何一部分失敗都會導(dǎo)致整個事務(wù)的回滾。
  • 一致性(Consistency):事務(wù)前后,數(shù)據(jù)庫應(yīng)保持一致的狀態(tài),即事務(wù)不應(yīng)破壞數(shù)據(jù)庫的完整性約束。(通過原子性,隔離性,持久性 AND 用戶的配合實現(xiàn)一致性)
    • 這表示寫入的資料必須完 全符合所有的預(yù)設(shè)規(guī)則,這包含資料的精確度、串聯(lián)性以及后續(xù)數(shù)據(jù)庫可以自發(fā)性地完成預(yù)定的工 作。
  • 隔離性(Isolation,又稱獨立性):事務(wù)之間的執(zhí)行是相互隔離的,一個事務(wù)的執(zhí)行不會受到其他事務(wù)的影響。
    • 允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個事務(wù) 并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。
    • 事務(wù)隔離分為不同級別,包括讀未提交( Read uncommitted )、讀提交(read committed)、可重復(fù)讀( repeatable read )和串行化 ( Serializable
  • 持久性(Durability):一旦事務(wù)提交,其對數(shù)據(jù)庫所做的改變將是 永久性 的,即使系統(tǒng)發(fā)生故障也不會丟失。

2.2 為什么存在事務(wù)

剛才說的是多個 sql交叉執(zhí)行 可能會出現(xiàn) 并發(fā)問題 ,進(jìn)而導(dǎo)致數(shù)據(jù)不一致,進(jìn)而導(dǎo)致數(shù)據(jù)完整性,這都知道。但是對事務(wù)的理解不能光站在程序員角度理解,一定要站在數(shù)據(jù)庫使用者角度考慮。

  • 事務(wù)被 MySQL 編寫者設(shè)計出來,但是 事務(wù) 并不是天然就有的,而是在用一段時間發(fā)現(xiàn)要有這個 事務(wù)。本質(zhì)是為了當(dāng)應(yīng)用程序訪問數(shù)據(jù)庫的時候,事務(wù) 能夠簡化我們的編程模型,不需要我們?nèi)タ紤]各種各樣的潛在錯誤和并發(fā)問題。
  • 只需要把告訴我你要干什么,把你的 sql 給我,我?guī)湍惴庋b成事務(wù),幫你去運行??梢韵胍幌庐?dāng)我們使用事務(wù)時,要么提交,要么回滾,我們不會去考慮網(wǎng)絡(luò)異常了,服務(wù)器宕機了,同時更改一個數(shù)據(jù)怎么辦對吧?這些問題統(tǒng)統(tǒng)不考慮。
  • 因此 事務(wù) 本質(zhì)上是為了應(yīng)用層服務(wù)的,是為了讓上層的應(yīng)用服務(wù)更好的使用數(shù)據(jù)庫。而不是伴隨著數(shù)據(jù)庫系統(tǒng)天生就有的。

備注:我們后面把 MySQL 中的一行信息,稱為 一行記錄

總結(jié)

  • 解決并發(fā)問題:事務(wù)的設(shè)計初衷是為了應(yīng)對并發(fā)操作帶來的數(shù)據(jù)不一致問題,確保數(shù)據(jù)的完整性和一致性。
  • 服務(wù)應(yīng)用層:事務(wù)的本質(zhì)是為應(yīng)用層服務(wù)的,它簡化了開發(fā)者的編程模型,使開發(fā)者可以專注于業(yè)務(wù)邏輯,而不用擔(dān)心底層的數(shù)據(jù)操作細(xì)節(jié)。
  • 對來的一大批 SQL–打包成事務(wù)-- 先描述再組織 管理

2.3 事務(wù)的版本支持

  • 支持引擎:在MySQL中,只有使用了 InnoDB 數(shù)據(jù)庫引擎的數(shù)據(jù)庫或表才
  • 支持事務(wù),MyISAM 不支持。

查看引擎

mysql> show engines \G;
# ...
*************************** 5. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
# ...
*************************** 7. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES
# ...
9 rows in set (0.01 sec)

2.4 事務(wù)的提交方式

  • 自動提交:事務(wù)默認(rèn)是自動提交的。
  • 手動提交

查看

show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+

設(shè)置

set autocommit=0; -- 設(shè)置為手動提交
set autocommit=1; -- 設(shè)置為自動提交

2.5 事務(wù)的常見操作方式

linux下 mysql 是一個命令行式的客戶端進(jìn)程。但不僅如此 mysql 客戶端還有很多其他客戶端如圖形化界面版的,還有其他語言版的。

  • mysql 是一套網(wǎng)絡(luò)服務(wù)進(jìn)程也就意味著除了本地主機,遠(yuǎn)端主機也可以連接 myql

換句話說 mysql 服務(wù)器可能會被多個客戶端同時訪問

root@VM-8-10-ubuntu:/home/lighthouse# netstat -nltp; # 需要切換成 root 用戶
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      13847/mysqld            
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      823/sshd: /usr/sbin 

為了更好做事務(wù)方面演示,我們將 mysql 的默認(rèn)隔離級別設(shè)置成讀未提交,隔離級別后面我們專門具體說。

設(shè)置全局事務(wù)隔離級別 讀為提交

set global transaction isolation level READ UNCOMMITTED;

需要重啟終端,進(jìn)行查看,可以看到

mysql> quit
Bye
# 需要重啟終端,進(jìn)行查看
mysql> select @@tx_isolation; # 5.0 版本
mysql> select @@transaction_isolation; # 8.0 版本
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
REPEATABLE-READ   # 默認(rèn)是這個
  • 然后新起兩個 mysql 客戶端,為什么這么做呢,我們主要是為了研究事務(wù),研究事務(wù)就要研究多個客戶端并發(fā)訪問的情況。
  • 其次 mysql 是有隔離性和隔離級別的,所以目前把隔離級別跳到最低,一個 mysql 做操作,另一個 mysql 就能看到。
  • 這樣很能清楚看到事務(wù)交叉所帶來的問題。

【案例】:

① 創(chuàng)建一個員工表

create table if not exists account(
	id int primary key,
	name varchar(50) not null default '',
	blance decimal(10,2) not null default 0.0
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;

兩個 mysql客戶端 可以并發(fā)訪問這張表,準(zhǔn)備工作全部就緒,下面我們來做試驗!

mysql> show processlist;
+------+-----------------+-----------+--------+---------+---------+------------------------+------------------+
| Id   | User            | Host      | db     | Command | Time    | State                  | Info             |
+------+-----------------+-----------+--------+---------+---------+------------------------+------------------+
|    5 | event_scheduler | localhost | NULL   | Daemon  | 4481367 | Waiting on empty queue | NULL             |
| 2385 | root            | localhost | learn3 | Query   |       0 | init                   | show processlist |
| 2386 | root            | localhost | learn3 | Sleep   |      41 |                        | NULL             |
+------+-----------------+-----------+--------+---------+---------+------------------------+------------------+

?正常演示 - 事務(wù)的開始與回滾

② 啟動事務(wù)

start transaction; -- 方式一
begin;  -- 方式二

③ 設(shè)置保存點

savepoint s1;

④ 回滾到保存點

rollback s1;

設(shè)置和回滾使用如下

⑤ 提交事務(wù)

如果想結(jié)束這個事務(wù),那就提交一下,相當(dāng)于把這個事務(wù)提交了

commit;

⑥ 回滾事務(wù)

  • 那我們以后是不是必須要設(shè)置保持點才能回滾呢?
  • 并不是!沒有保存點只是沒有辦法定向回滾了。但是可以直接回滾到最開始!
rollback;

直接回滾到最開始!然后數(shù)據(jù)就全沒了。即使是結(jié)束事務(wù),回歸到單 sql 也是沒有的。

非正常操作

下面都是默認(rèn)開啟 自動提交 的,而且 演示 1 和 演示 2 表開始的時候均無數(shù)據(jù)(empty)

非正常演示1: 證明未 commit ,客戶端崩潰,MySQL自動會回滾(隔離級別設(shè)置為讀未提交)

-- 終端A
begin; -- 開啟事務(wù)
insert into account values (1, '張三', 100); -- 插入記錄
mysql> select * from account; -- 數(shù)據(jù)已經(jīng)存在,但沒有commit,此時同時查看終端B
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三    | 100.00 |
+----+--------+--------+

讓 A 中止,然后再查看A終止前后 B 的數(shù)據(jù),如下:

mysql> Aborted -- ctrl + \ 異常終止MySQL
-- 終端B
mysql> select * from account; -- 終端 A 崩潰前
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三    | 100.00 |
+----+--------+--------+
1 row in set (0.00 sec)
mysql> select * from account; -- 終端 A 崩潰后
Empty set (0.00 sec)

上面我們發(fā)現(xiàn) 數(shù)據(jù)自動進(jìn)行了回滾

非正常演示2 - 證明 commit 了,客戶端崩潰,MySQL數(shù)據(jù)不會在受影響,已經(jīng)持久化

-- 終端 A
mysql> begin;                    -- 開啟事務(wù)
mysql> insert into account values (1, '張三', 100); -- 插入記錄
Query OK, 1 row affected (0.00 sec)
mysql> commit; -- 提交事務(wù)
Query OK, 0 rows affected (0.04 sec)
mysql> Aborted -- ctrl + \ 異常終止MySQL
-- 終端 A 終止后,切換終端 B 查看數(shù)據(jù)
mysql> select * from account;
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三    | 100.00 |
+----+--------+--------+
1 row in set (0.00 sec)

相比于上面這里我們在異常終止終端 A 之前,已經(jīng)把數(shù)據(jù) commit 了,然后再查看 B 發(fā)現(xiàn)數(shù)據(jù)還在,沒有回滾 – 持久化保存

  • 數(shù)據(jù)存在了,所以commit 的作用是將數(shù)據(jù)持久化到MySQL中

非正常演示3 - 對比演示 1。證明 begin 操作會自動更改提交方式,不會受 MySQL 是否自動提交影響

-- 終端 A,歷史是有數(shù)據(jù)的
mysql> select * from account; 
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三    | 100.00 |
+----+--------+--------+
-- 事務(wù) A 開始時: 是默認(rèn)自動提交的查
mysql> show variables like 'autocommit'; 
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)
-- 關(guān)閉自動提交
mysql> set autocommit=0; 
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+

然后再開始進(jìn)行事務(wù)操作,如下:

mysql> begin; -- 開啟事務(wù)
mysql> insert into account values (2, '李四', 10000); -- 插入記錄
-- 在終端 A 中查看插入記錄
mysql> select *from account; 
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四    | 10000.00 |
+----+--------+----------+

然后再次讓終端 A 異常終止,查看 A 終止前后 B 的數(shù)據(jù),如下:

mysql> Aborted -- 再次異常終止 A 
-- 切換到終端 B
mysql> select * from account; -- 終端A崩潰前
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四   | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> select * from account; -- 終端A崩潰后,自動回滾
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三    | 100.00 |
+----+--------+--------+

此時我們發(fā)現(xiàn),這個結(jié)果和 演示1 是類似的,可以知道 begin 與是否設(shè)置 set autocommit 無關(guān),證明正確

④ 非正常演示4 - 證明單條 SQL 與事務(wù)的關(guān)系【autocommit】

實驗一:

-- 終端 A,開始時是有數(shù)據(jù)的
mysql> select * from account;
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三   | 100.00 |
+----+--------+--------+
mysql> set autocommit=0; -- 關(guān)閉自動提交
mysql> insert into account values (2, '李四', 10000); -- 插入記錄
Query OK, 1 row affected (0.00 sec)
mysql> select *from account; -- 在終端 A 中查看結(jié)果,已經(jīng)插入。此時可以在查看終端B
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四    | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> ^D Bye -- ctrl + \ or ctrl + d,終止終端 
-- 終端B
mysql> select * from account; -- 終端A崩潰前
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四    | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> select * from account; -- 終端A崩潰后
+----+--------+--------+
| id | name   | blance |
+----+--------+--------+
| 1  | 張三   | 100.00 |
+----+--------+--------+

上面數(shù)據(jù)發(fā)生了回滾

實驗二:

-- 終端A
mysql> show variables like 'autocommit'; -- 開啟默認(rèn)提交
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON     |
+---------------+-------+
1 row in set (0.00 sec)
mysql> insert into account values (2, '李四', 10000);
mysql> select * from account; -- 數(shù)據(jù)已經(jīng)插入
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四    | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> Aborted -- 異常終止
-- 終端B
mysql> select * from account; -- 終端A崩潰前
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四    | 10000.00 |
+----+--------+----------+
mysql> select * from account; -- 終端A崩潰后,并不影響,已經(jīng)持久化。autocommit起作用
+----+--------+----------+
| id | name   | blance   |
+----+--------+----------+
| 1  | 張三    | 100.00   |
| 2  | 李四    | 10000.00 |
+----+--------+----------+

結(jié)論

  • 未提交時客戶端崩潰:事務(wù)可以手動回滾,同時操作異常時,MySQL 會自動回滾未提交的事務(wù)。
  • 已提交時客戶端崩潰:只要輸入begin 或者 start transaction,事務(wù)便必須要通過 commit 提交,才會持久化,與是否設(shè)置 set autocommit 無關(guān)
  • 單條SQL與事務(wù):默認(rèn)情況下,對于 InnoDB 每一條 SQL 語言都默認(rèn)封裝成事務(wù),自動提交。如果關(guān)閉自動提交,單條SQL語句也需要手動提交或回滾【select 有特殊情況,因為 MySQL 有 MVCC】

從上面的例子,我們能看到事務(wù)本身的原子性(回滾),持久性(commit)

注意事項

  • 回滾:如果沒有設(shè)置保存點,只能回滾到事務(wù)的開始,直接使用 rollback(前提是事務(wù) 還沒有提交)
  • 提交:事務(wù)提交后無法回滾。
  • 保存點:可以選擇回退到哪個保存點。
  • 版本支持InnoDB 支持事務(wù), MyISAM 不支持事務(wù)
  • 啟動事務(wù):可以使用 start transactionbegin

到此這篇關(guān)于MySQL 事務(wù)的概念及ACID屬性和使用詳解的文章就介紹到這了,更多相關(guān)mysql事務(wù)ACID屬性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL中union和unionall區(qū)別

    MySQL中union和unionall區(qū)別

    本文主要介紹了MySQL中union和unionall區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • mysql自聯(lián)去重的一些筆記記錄

    mysql自聯(lián)去重的一些筆記記錄

    這篇文章主要給大家介紹了關(guān)于mysql自聯(lián)去重的一些筆記記錄,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用mysql具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • MySQL關(guān)于exists的一個bug

    MySQL關(guān)于exists的一個bug

    今天小編給大家分享一個mysql關(guān)于exists的一個bug問題,非常不錯,感興趣的朋友一起學(xué)習(xí)下
    2016-08-08
  • MySQL數(shù)據(jù)庫備份和還原的常用命令小結(jié)

    MySQL數(shù)據(jù)庫備份和還原的常用命令小結(jié)

    MySQL數(shù)據(jù)庫備份和還原的常用命令小結(jié),學(xué)習(xí)mysql的朋友可以參考下
    2012-03-03
  • Mysql指定某個字符串字段前面幾位排序查詢方式

    Mysql指定某個字符串字段前面幾位排序查詢方式

    這篇文章主要介紹了Mysql指定某個字符串字段前面幾位排序查詢方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • mysql中GROUP_CONCAT的使用方法實例分析

    mysql中GROUP_CONCAT的使用方法實例分析

    這篇文章主要介紹了mysql中GROUP_CONCAT的使用方法,結(jié)合實例形式分析了MySQL中GROUP_CONCAT合并查詢結(jié)果的相關(guān)操作技巧,需要的朋友可以參考下
    2020-02-02
  • MySQL MGR搭建過程中常遇見的問題及解決辦法

    MySQL MGR搭建過程中常遇見的問題及解決辦法

    這篇文章主要介紹了MySQL MGR搭建過程中常遇見的問題及解決辦法,幫助大家更好的理解和學(xué)習(xí)使用MySQL,感興趣的朋友可以了解下
    2021-03-03
  • MySQL基礎(chǔ)教程之DML語句詳解

    MySQL基礎(chǔ)教程之DML語句詳解

    DML 語句是指對數(shù)據(jù)庫中表的記錄進(jìn)行的操作,下面這篇文章主要給大家介紹了關(guān)于MySQL基礎(chǔ)教程之DML語句的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • MySQL常用的日期時間函數(shù)匯總(附實例)

    MySQL常用的日期時間函數(shù)匯總(附實例)

    日期時間處理對大家來說應(yīng)該都不陌生了,下面這篇文章主要給大家介紹了關(guān)于MySQL常用的日期時間函數(shù),文中通過圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用mysql具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-03-03
  • Mysql按特定符號分割成多行和多列的示例

    Mysql按特定符號分割成多行和多列的示例

    本文主要介紹了Mysql 按特定符號分割成多行和多列,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論