久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

mysql事務的含義是什么

132次閱讀
沒有評論

共計 15010 個字符,預計需要花費 38 分鐘才能閱讀完成。

這篇文章主要介紹了 mysql 事務的含義是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇 mysql 事務的含義是什么文章都會有所收獲,下面我們一起來看看吧。

mysql 事務是指對數據庫執行一批操作,在同一個事務當中,這些操作最終要么全部執行成功,要么全部失敗,不會存在部分成功的情況;事務是一個原子操作,是一個最小執行單元,可以由一個或多個 SQL 語句組成。

什么是事務?

數據庫中的事務是指對數據庫執行一批操作,在同一個事務當中,這些操作最終要么全部執行成功,要么全部失敗,不會存在部分成功的情況。

事務是一個原子操作。是一個最小執行單元。可以由一個或多個 SQL 語句組成

在同一個事務當中,所有的 SQL 語句都成功執行時,整 個事務成功,有一個 SQL 語句執行失敗,整個事務都執行失敗。

舉個例子:

比如 A 用戶給 B 用戶轉賬 100 操作,過程如下:

從 A 賬戶扣 100

給 B 賬戶加 100

如果在事務的支持下,上面最終只有 2 種結果:

操作成功:A 賬戶減少 100;B 賬戶增加 100

操作失敗:A、B 兩個賬戶都沒有發生變化

如果沒有事務的支持,可能出現錯:A 賬戶減少了 100,此時系統掛了,導致 B 賬戶沒有加上 100,而 A 賬戶憑空少了 100。

事務的幾個特性 (ACID) - 重點原子性 (Atomicity)

事務的整個過程如原子操作一樣,最終要么全部成功,或者全部失敗,這個原子性是從最終結果來看的,從最終結果來看這個過程是不可分割的。

一致性 (Consistency)

一個事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態。

首先回顧一下一致性的定義。所謂一致性,指的是數據處于一種有意義的狀態,這種狀態是語義上的而不是語法上的。最常見的例子是轉帳。例如從帳戶 A 轉一筆錢到帳戶 B 上,如果帳戶 A 上的錢減少了,而帳戶 B 上的錢卻沒有增加,那么我們認為此時數據處于不一致的狀態。

從這段話的理解來看,所謂一致性,即,從實際的業務邏輯上來說,最終結果是對的、是跟程序員的所期望的結果完全符合的

隔離性 (Isolation)

一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對并發的其他事務是隔離的,并發執行的各個事務之間不能互相干擾。

這里先提一下事務的隔離級別:

讀未提交:read uncommitted

讀已提交:read committed

可重復讀:repeatable read

串行化:serializable

持久性 (Durability)

一個事務一旦提交,他對數據庫中數據的改變就應該是永久性的。當事務提交之后,數據會持久化到硬盤,修改是永久性的。

Mysql 中事務操作

mysql 中事務默認是隱式事務,執行 insert、update、delete 操作的時候,數據庫自動開啟事務、提交或回滾事務。

是否開啟隱式事務是由變量 autocommit 控制的。

所以事務分為隱式事務和顯式事務。

隱式事務

事務自動開啟、提交或回滾,比如 insert、update、delete 語句,事務的開啟、提交或回滾由 mysql 內部自動控制的。

查看變量 autocommit 是否開啟了自動提交

mysql show variables like autocommit +---------------+-------+| Variable_name | Value |+---------------+-------+| autocommit   | ON   |+---------------+-------+1 row in set, 1 warning (0.00 sec)

autocommit 為 ON 表示開啟了自動提交。

顯式事務

事務需要手動開啟、提交或回滾,由開發者自己控制。

2 種方式手動控制事務:

方式 1:

語法:

// 設置不自動提交事務 set autocommit=0;// 執行事務操作 commit|rollback;

示例 1:提交事務操作,如下:

mysql create table test1 (a int);Query OK, 0 rows affected (0.01 sec)mysql select * from test1;Empty set (0.00 sec)mysql set autocommit=0;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values(1);Query OK, 1 row affected (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)

示例 2:回滾事務操作,如下:

mysql set autocommit=0;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values(2);Query OK, 1 row affected (0.00 sec)mysql rollback;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)

可以看到上面數據回滾了。

我們把 autocommit 還原回去:

mysql set autocommit=1;Query OK, 0 rows affected (0.00 sec)

方式 2:

語法:

start transaction;// 開啟事務 // 執行事務操作 commit|rollback;

示例 1:提交事務操作,如下:

mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values (2);Query OK, 1 row affected (0.00 sec)mysql insert into test1 values (3);Query OK, 1 row affected (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 ||   2 ||   3 |+------+3 rows in set (0.00 sec)

上面成功插入了 2 條數據。

示例 2:回滾事務操作,如下:

mysql select * from test1;+------+| a   |+------+|   1 ||   2 ||   3 |+------+3 rows in set (0.00 sec)mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql delete from test1;Query OK, 3 rows affected (0.00 sec)mysql rollback;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 ||   2 ||   3 |+------+3 rows in set (0.00 sec)

上面事務中我們刪除了 test1 的數據,顯示刪除了 3 行,最后回滾了事務。

savepoint 關鍵字

在事務中我們執行了一大批操作,可能我們只想回滾部分數據,怎么做呢?

我們可以將一大批操作分為幾個部分,然后指定回滾某個部分。可以使用 savepoin 來實現,效果如下:

先清除 test1 表數據:

mysql delete from test1;Query OK, 3 rows affected (0.00 sec)mysql select * from test1;Empty set (0.00 sec)

演示 savepoint 效果,認真看:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql savepoint part1;// 設置一個保存點 Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values (2);Query OK, 1 row affected (0.00 sec)mysql rollback to part1;// 將 savepint = part1 的語句到當前語句之間所有的操作回滾 Query OK, 0 rows affected (0.00 sec)mysql commit;// 提交事務 Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)

從上面可以看出,執行了 2 次插入操作,最后只插入了 1 條數據。

savepoint 需要結合 rollback to sp1 一起使用,可以將保存點 sp1 到 rollback to 之間的操作回滾掉。

只讀事務

表示在事務中執行的是一些只讀操作,如查詢,但是不會做 insert、update、delete 操作,數據庫內部對只讀事務可能會有一些性能上的優化。

用法如下:

start transaction read only;

示例:

mysql commit;Query OK, 0 rows affected (0.00 sec)mysql start transaction read only;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)mysql delete from test1;ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.mysql commit;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)

只讀事務中執行 delete 會報錯。

事務中的一些問題(重點)

這些問題主要是基于數據在多個事務中的可見性來說的。也是并發事務產生的問題。

更新丟失

丟失更新就是兩個不同的事務(或者 Java 程序線程)在某一時刻對同一數據進行讀取后,先后進行修改。導致第一次操作數據丟失。

第一類丟失更新:A,B 事務同時操作同一數據,A 先對改數據進行了更改,B 再次更改時失敗然后回滾,把 A 更新的數據也回滾了。(事務撤銷造成的撤銷丟失)

第二類丟失更新:A,B 事務同時操作同一數據,A 先對改數據進行了更改,B 再次更改并且提交,把 A 提交的數據給覆蓋了。(事務提交造成的覆蓋丟失)

臟讀

一個事務在執行的過程中讀取到了其他事務還沒有提交的數據。這個還是比較好理解的。

兩個事務同時操作同一數據,A 事務對該數據進行了修改還沒提交的時候,B 事務訪問了該條事務,并且使用了該數據,此時 A 事務回滾,那么 B 事務讀到的就是臟數據。

比如事務 1,修改了某個數據 事務 2,剛好訪問了事務 1 修改后的數據

此時事務 1,回滾了操作 事務 2,讀到還是回滾前的數據

讀已提交

從字面上我們就可以理解,即一個事務操作過程中可以讀取到其他事務已經提交的數據。

事務中的每次讀取操作,讀取到的都是數據庫中其他事務已提交的最新的數據(相當于當前讀)

不可重復讀

在同一事務中,多次讀取同一數據返回的結果有所不同,換句話說,后續讀取可以讀到另一事務已提交的更新數據。相反,“可重復讀”在同一事務中多次讀取數據時, 能夠保證所讀數據一樣, 也就是后續讀取不能讀到另一事務已提交的更新數據。

這種情況發生 在一個事務內多次讀同一數據。A 事務查詢某條數據,該事務未結束時,B 事務也訪問同一數據并進行了修改。那么在 A 事務中的兩 次讀數據之間,由于第二個事務的修改,那么第一個事務兩次讀到的的數據可能是不一樣的。

事務 1,查詢某個數據 事務 2,修改了某個數據,提交

事務 1,再次查詢這個數據

這樣事務 1 兩次查詢的數據不一樣,稱為不可重復讀

可重復讀

一個事務操作中對于一個讀取操作不管多少次,讀取到的結果都是一樣的。

幻讀

臟讀、不可重復讀、可重復讀、幻讀,其中最難理解的是幻讀

以 mysql 為例:

幻讀現象例子:

可重復讀模式下,比如有個用戶表,手機號碼為主鍵,有兩個事物進行如下操作

事務 A 操作如下:1、打開事務 2、查詢號碼為 X 的記錄,不存在 3、插入號碼為 X 的數據,插入報錯(為什么會報錯,先向下看)4、查詢號碼為 X 的記錄,發現還是不存在(由于是可重復讀,所以讀取記錄 X 還是不存在的)

事物 B 操作:在事務 A 第 2 步操作時插入了一條 X 的記錄,所以會導致 A 中第 3 步插入報錯(違反了唯一約束)

上面操作對 A 來說就像發生了幻覺一樣,明明查詢 X(A 中第二步、第四步)不存在,但卻無法插入成功

幻讀可以這么理解:事務中后面的操作(插入號碼 X)需要上面的讀取操作(查詢號碼 X 的記錄)提供支持,但讀取操作卻不能支持下面的操作時產生的錯誤,就像發生了幻覺一樣。

看第二種解釋:

事務 A 在操作一堆數據的時候,事務 B 插入了一條數據,A 事務再次(第二次)查詢,發現多了一條數據,像是幻覺。與不可重復讀類似,不同的是一個是修改刪除操作,一個是新增操作。

如果還是理解不了的,繼續向下看,后面后詳細的演示。

事務的隔離級別

當多個事務同時進行的時候,如何確保當前事務中數據的正確性,比如 A、B 兩個事物同時進行的時候,A 是否可以看到 B 已提交的數據或者 B 未提交的數據,這個需要依靠事務的隔離級別來保證,不同的隔離級別中所產生的效果是不一樣的。

事務隔離級別主要是解決了上面多個事務之間數據可見性及數據正確性的問題。(或者說為了解決并發控制可能產生的異常問題,數據庫定義了四種事務的隔離級別)

隔離級別分為 4 種:

讀未提交:READ-UNCOMMITTED

讀已提交:READ-COMMITTED

可重復讀:REPEATABLE-READ

串行:SERIALIZABLE

上面 4 中隔離級別越來越強,會導致數據庫的并發性也越來越低。

查看隔離級別

mysql show variables like transaction_isolation +-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | READ-COMMITTED |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)

隔離級別的設置

分 2 步驟,修改文件、重啟 mysql,如下:

修改 mysql 中的 my.init 文件,我們將隔離級別設置為:READ-UNCOMMITTED,如下:

# 隔離級別設置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復讀,SERIALIZABLE 串行 transaction-isolation=READ-UNCOMMITTED

以管理員身份打開 cmd 窗口,重啟 mysql,如下:

C:\Windows\system32 net stop mysql
mysql 服務正在停止..mysql 服務已成功停止。

C:\Windows\system32 net start mysql
mysql 服務正在啟動 .mysql 服務已經啟動成功。

各種隔離級別中會出現的問題隔離級別臟讀可能性不可重復讀可能性幻讀可能性 READ-UNCOMMITTED 有有有 READ-COMMITTED 無有有 REPEATABLE-READ 無無有 SERIALIZABLE 無無無

下面我們來演示一下,各種隔離級別中可見性的問題,開啟兩個窗口,叫做 A、B 窗口,兩個窗口中登錄 mysql。

READ-UNCOMMITTED:讀未提交

將隔離級別置為 READ-UNCOMMITTED:

# 隔離級別設置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復讀,SERIALIZABLE 串行 transaction-isolation=READ-UNCOMMITTED

重啟 mysql:

C:\Windows\system32 net stop mysql
mysql 服務正在停止..mysql 服務已成功停止。

C:\Windows\system32 net start mysql
mysql 服務正在啟動 .mysql 服務已經啟動成功。

查看隔離級別:

mysql show variables like transaction_isolation +-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | READ-UNCOMMITTED |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)

先清空 test1 表數據:

delete from test1;select * from test1;

按時間順序在 2 個窗口中執行下面操作:

時間窗口 A 窗口 BT1start transaction;
T2select * from test1;
T3
start transaction;T4
insert into test1 values (1);T5
select * from test1;T6select * from test1;
T7
commit;T8commit;

A 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;Empty set (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

B 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

看一下:

T2-A:無數據,T6-A:有數據,T6 時刻 B 還未提交,此時 A 已經看到了 B 插入的數據,說明出現了臟讀。

T2-A:無數據,T6-A:有數據,查詢到的結果不一樣,說明不可重復讀。

結論:讀未提交情況下,可以讀取到其他事務還未提交的數據,多次讀取結果不一樣,出現了臟讀、不可重復讀、幻讀

READ-COMMITTED:讀已提交

將隔離級別置為 READ-COMMITTED

# 隔離級別設置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復讀,SERIALIZABLE 串行 transaction-isolation=READ-COMMITTED

重啟 mysql:

C:\Windows\system32 net stop mysql
mysql 服務正在停止..mysql 服務已成功停止。

C:\Windows\system32 net start mysql
mysql 服務正在啟動 .mysql 服務已經啟動成功。

查看隔離級別:

mysql show variables like transaction_isolation +-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | READ-COMMITTED |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)

先清空 test1 表數據:

delete from test1;select * from test1;

按時間順序在 2 個窗口中執行下面操作:

時間窗口 A 窗口 BT1start transaction;
T2select * from test1;
T3
start transaction;T4
insert into test1 values (1);T5
select * from test1;T6select * from test1;
T7
commit;T8select * from test1;
T9commit;

A 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;Empty set (0.00 sec)mysql select * from test1;Empty set (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

B 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

看一下:

T5-B:有數據,T6- A 窗口:無數據,A 看不到 B 的數據,說明沒有臟讀。

T6- A 窗口:無數據,T8-A:看到了 B 插入的數據,此時 B 已經提交了,A 看到了 B 已提交的數據,說明可以讀取到已提交的數據。

T2-A、T6-A:無數據,T8-A:有數據,多次讀取結果不一樣,說明不可重復讀。

結論:讀已提交情況下,無法讀取到其他事務還未提交的數據,可以讀取到其他事務已經提交的數據,多次讀取結果不一樣,未出現臟讀,出現了讀已提交、不可重復讀、幻讀

REPEATABLE-READ:可重復讀

將隔離級別置為 REPEATABLE-READ

# 隔離級別設置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復讀,SERIALIZABLE 串行 transaction-isolation=REPEATABLE-READ

重啟 mysql:

C:\Windows\system32 net stop mysql
mysql 服務正在停止..mysql 服務已成功停止。

C:\Windows\system32 net start mysql
mysql 服務正在啟動 .mysql 服務已經啟動成功。

查看隔離級別:

mysql show variables like transaction_isolation +-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | REPEATABLE-READ |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)

先清空 test1 表數據:

delete from test1;select * from test1;

按時間順序在 2 個窗口中執行下面操作:

時間窗口 A 窗口 BT1start transaction;
T2select * from test1;
T3
start transaction;T4
insert into test1 values (1);T5
select * from test1;T6select * from test1;
T7
commit;T8select * from test1;
T9commit;
T10select * from test1;

A 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;Empty set (0.00 sec)mysql select * from test1;Empty set (0.00 sec)mysql select * from test1;Empty set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)

B 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

看一下:

T2-A、T6- A 窗口:無數據,T5-B:有數據,A 看不到 B 的數據,說明沒有臟讀。

T8-A:無數據,此時 B 已經提交了,A 看不到 B 已提交的數據,A 中 3 次讀的結果一樣都是沒有數據的,說明可重復讀。

結論:可重復讀情況下,未出現臟讀,未讀取到其他事務已提交的數據,多次讀取結果一致,即可重復讀。

幻讀演示

將隔離級別置為 REPEATABLE-READ

# 隔離級別設置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復讀,SERIALIZABLE 串行 transaction-isolation=REPEATABLE-READ

重啟 mysql:

C:\Windows\system32 net stop mysql
mysql 服務正在停止..mysql 服務已成功停止。

C:\Windows\system32 net start mysql
mysql 服務正在啟動 .mysql 服務已經啟動成功。

查看隔離級別:

mysql show variables like transaction_isolation +-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | REPEATABLE-READ |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)

準備數據:

mysql create table t_user(id int primary key,name varchar(16) unique key);Query OK, 0 rows affected (0.01 sec)mysql insert into t_user values (1, 路人甲 Java),(2, 路人甲 Java ERROR 1062 (23000): Duplicate entry 路人甲 Java ***\*for\**** key name mysql select * from t_user;Empty set (0.00 sec)

上面我們創建 t_user 表,name 添加了唯一約束,表示 name 不能重復,否則報錯。

按時間順序在 2 個窗口中執行下面操作:

時間窗口 A 窗口 BT1start transaction;
T2
start transaction;T3
– 插入路人甲 Java
insert into t_user values (1,‘路人甲 Java’);T4
select * from t_user;T5– 查看路人甲 Java 是否存在
select * from t_user where name=‘路人甲 Java’;
T6
commit;T7– 插入路人甲 Java
insert into t_user values (2,‘路人甲 Java’);
T8– 查看路人甲 Java 是否存在
select * from t_user where name=‘路人甲 Java’;
T9commit;

A 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql select * from t_user where name= 路人甲 Java Empty set (0.00 sec)mysql insert into t_user values (2, 路人甲 Java ERROR 1062 (23000): Duplicate entry 路人甲 Java ***\*for\**** key name mysql select * from t_user where name= 路人甲 Java Empty set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

B 窗口如下:

mysql start transaction;Query OK, 0 rows affected (0.00 sec)mysql insert into t_user values (1, 路人甲 Java Query OK, 1 row affected (0.00 sec)mysql select * from t_user;+----+---------------+| id | name      |+----+---------------+|  1 | 路人甲 Java   |+----+---------------+1 row in set (0.00 sec)mysql commit;Query OK, 0 rows affected (0.00 sec)

看一下:

A 想插入數據路人甲 Java,插入之前先查詢了一下(T5 時刻)該用戶是否存在,發現不存在,然后在 T7 時刻執行插入,報錯了,報數據已經存在了,因為 T6 時刻 B 已經插入了路人甲 Java。

然后 A 有點郁悶,剛才查的時候不存在的,然后 A 不相信自己的眼睛,又去查一次(T8 時刻),發現路人甲 Java 還是不存在的。

此時 A 心里想:數據明明不存在啊,為什么無法插入呢?這不是懵逼了么,A 覺得如同發生了幻覺一樣。

SERIALIZABLE:串行

SERIALIZABLE 會讓并發的事務串行執行(多個事務之間讀寫、寫讀、寫寫會產生互斥,效果就是串行執行,多個事務之間的讀讀不會產生互斥)。

讀寫互斥:事務 A 中先讀取操作,事務 B 發起寫入操作,事務 A 中的讀取會導致事務 B 中的寫入處于等待狀態,直到 A 事務完成為止。

表示我開啟一個事務,為了保證事務中不會出現上面說的問題(臟讀、不可重復讀、讀已提交、幻讀),那么我讀取的時候,其他事務有修改數據的操作需要排隊等待,等待我讀取完成之后,他們才可以繼續。

寫讀、寫寫也是互斥的,讀寫互斥類似。

這個類似于 java 中的 java.util.concurrent.lock.ReentrantReadWriteLock 類產生的效果。

下面演示讀寫互斥的效果。

將隔離級別置為 SERIALIZABLE

# 隔離級別設置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復讀,SERIALIZABLE 串行 transaction-isolation=SERIALIZABLE

重啟 mysql:

C:\Windows\system32 net stop mysql
mysql 服務正在停止..mysql 服務已成功停止。

C:\Windows\system32 net start mysql
mysql 服務正在啟動 .mysql 服務已經啟動成功。

查看隔離級別:

mysql show variables like transaction_isolation +-----------------------+--------------+| Variable_name     | Value     |+-----------------------+--------------+| transaction_isolation | SERIALIZABLE |+-----------------------+--------------+1 row in set, 1 warning (0.00 sec)

先清空 test1 表數據:

delete from test1;select * from test1;

按時間順序在 2 個窗口中執行下面操作:

時間窗口 A 窗口 BT1start transaction;
T2select * from test1;
T3
start transaction;T4
insert into test1 values (1);T5commit;
T6
commit;

按時間順序運行上面的命令,會發現 T4- B 這樣會被阻塞,直到 T5- A 執行完畢。

上面這個演示的是讀寫互斥產生的效果,大家可以自己去寫一下寫讀、寫寫互斥的效果。

可以看出來,事務只能串行執行了。串行情況下不存在臟讀、不可重復讀、幻讀的問題了。

小結

讀未提交 (Read Uncommitted)

讀未提交是隔離級別最低的一種事務級別。在這種隔離級別下,一個事務會讀到另一個事務更新后但未提交的數據,如果另一個事務回滾,那么當前事務讀到的數據就是臟數據,這就是臟讀(Dirty Read)。

讀已提交 (Read Committed)

在 Read Committed 隔離級別下,一個事務可能會遇到不可重復讀(Non Repeatable Read)的問題。不可重復讀是指,在一個事務內,多次讀同一數據,在這個事務還沒有結束時,如果另一個事務恰好修改了這個數據,那么,在第一個事務中,兩次讀取的數據就可能不一致。

可重復讀 (Repeatable Read)

在 Repeatable Read 隔離級別下,一個事務可能會遇到幻讀(Phantom Read)的問題。幻讀是指,在一個事務中,第一次查詢某條記錄,發現沒有,但是,當試圖更新這條不存在的記錄時,竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現了。幻讀就是沒有讀到的記錄,以為不存在,但其實是可以更新成功的,并且,更新成功后,再次讀取,就出現了。

可串行化 (Serializable)

Serializable 是最嚴格的隔離級別。在 Serializable 隔離級別下,所有事務按照次序依次執行,因此,臟讀、不可重復讀、幻讀都不會出現。

雖然 Serializable 隔離級別下的事務具有最高的安全性,但是,由于事務是串行執行,所以效率會大大下降,應用程序的性能會急劇降低。如果沒有特別重要的情景,一般都不會使用 Serializable 隔離級別。

默認隔離級別:如果沒有指定隔離級別,數據庫就會使用默認的隔離級別。在 MySQL 中,如果使用 InnoDB,默認的隔離級別是 Repeatable Read。

關于隔離級別的選擇

需要對各種隔離級別產生的現象非常了解,然后選擇的時候才能游刃有余

隔離級別越高,并發性也低,比如最高級別 SERIALIZABLE 會讓事物串行執行,并發操作變成串行了,會導致系統性能直接降低。

具體選擇哪種需要結合具體的業務來選擇。

讀已提交(READ-COMMITTED)通常用的比較多。

關于“mysql 事務的含義是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“mysql 事務的含義是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注丸趣 TV 行業資訊頻道。

向 AI 問一下細節

丸趣 TV 網 – 提供最優質的資源集合!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2024-02-03發表,共計15010字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 镇巴县| 正宁县| 朝阳区| 晴隆县| 资兴市| 随州市| 武穴市| 台南县| 绵竹市| 商都县| 西安市| 宁波市| 罗山县| 马关县| 涟水县| 株洲县| 连南| 遂昌县| 仁布县| 壶关县| 泗水县| 汉川市| 和田县| 达拉特旗| 安义县| 德庆县| 泉州市| 上林县| 平度市| 沂水县| 大同市| 闻喜县| 桃园市| 南郑县| 尤溪县| 尖扎县| 瑞金市| 永昌县| 多伦县| 鄱阳县| 梓潼县|