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

mysql事務(wù)的含義是什么

共計(jì) 15010 個(gè)字符,預(yù)計(jì)需要花費(fèi) 38 分鐘才能閱讀完成。

這篇文章主要介紹了 mysql 事務(wù)的含義是什么的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇 mysql 事務(wù)的含義是什么文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。

mysql 事務(wù)是指對(duì)數(shù)據(jù)庫(kù)執(zhí)行一批操作,在同一個(gè)事務(wù)當(dāng)中,這些操作最終要么全部執(zhí)行成功,要么全部失敗,不會(huì)存在部分成功的情況;事務(wù)是一個(gè)原子操作,是一個(gè)最小執(zhí)行單元,可以由一個(gè)或多個(gè) SQL 語(yǔ)句組成。

什么是事務(wù)?

數(shù)據(jù)庫(kù)中的事務(wù)是指對(duì)數(shù)據(jù)庫(kù)執(zhí)行一批操作,在同一個(gè)事務(wù)當(dāng)中,這些操作最終要么全部執(zhí)行成功,要么全部失敗,不會(huì)存在部分成功的情況。

事務(wù)是一個(gè)原子操作。是一個(gè)最小執(zhí)行單元。可以由一個(gè)或多個(gè) SQL 語(yǔ)句組成

在同一個(gè)事務(wù)當(dāng)中,所有的 SQL 語(yǔ)句都成功執(zhí)行時(shí),整 個(gè)事務(wù)成功,有一個(gè) SQL 語(yǔ)句執(zhí)行失敗,整個(gè)事務(wù)都執(zhí)行失敗。

舉個(gè)例子:

比如 A 用戶給 B 用戶轉(zhuǎn)賬 100 操作,過(guò)程如下:

從 A 賬戶扣 100

給 B 賬戶加 100

如果在事務(wù)的支持下,上面最終只有 2 種結(jié)果:

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

操作失敗:A、B 兩個(gè)賬戶都沒(méi)有發(fā)生變化

如果沒(méi)有事務(wù)的支持,可能出現(xiàn)錯(cuò):A 賬戶減少了 100,此時(shí)系統(tǒng)掛了,導(dǎo)致 B 賬戶沒(méi)有加上 100,而 A 賬戶憑空少了 100。

事務(wù)的幾個(gè)特性 (ACID) - 重點(diǎn)原子性 (Atomicity)

事務(wù)的整個(gè)過(guò)程如原子操作一樣,最終要么全部成功,或者全部失敗,這個(gè)原子性是從最終結(jié)果來(lái)看的,從最終結(jié)果來(lái)看這個(gè)過(guò)程是不可分割的。

一致性 (Consistency)

一個(gè)事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變換到另一個(gè)一致性狀態(tài)。

首先回顧一下一致性的定義。所謂一致性,指的是數(shù)據(jù)處于一種有意義的狀態(tài),這種狀態(tài)是語(yǔ)義上的而不是語(yǔ)法上的。最常見(jiàn)的例子是轉(zhuǎn)帳。例如從帳戶 A 轉(zhuǎn)一筆錢到帳戶 B 上,如果帳戶 A 上的錢減少了,而帳戶 B 上的錢卻沒(méi)有增加,那么我們認(rèn)為此時(shí)數(shù)據(jù)處于不一致的狀態(tài)。

從這段話的理解來(lái)看,所謂一致性,即,從實(shí)際的業(yè)務(wù)邏輯上來(lái)說(shuō),最終結(jié)果是對(duì)的、是跟程序員的所期望的結(jié)果完全符合的

隔離性 (Isolation)

一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾。即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾。

這里先提一下事務(wù)的隔離級(jí)別:

讀未提交:read uncommitted

讀已提交:read committed

可重復(fù)讀:repeatable read

串行化:serializable

持久性 (Durability)

一個(gè)事務(wù)一旦提交,他對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就應(yīng)該是永久性的。當(dāng)事務(wù)提交之后,數(shù)據(jù)會(huì)持久化到硬盤,修改是永久性的。

Mysql 中事務(wù)操作

mysql 中事務(wù)默認(rèn)是隱式事務(wù),執(zhí)行 insert、update、delete 操作的時(shí)候,數(shù)據(jù)庫(kù)自動(dòng)開啟事務(wù)、提交或回滾事務(wù)。

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

所以事務(wù)分為隱式事務(wù)和顯式事務(wù)。

隱式事務(wù)

事務(wù)自動(dòng)開啟、提交或回滾,比如 insert、update、delete 語(yǔ)句,事務(wù)的開啟、提交或回滾由 mysql 內(nèi)部自動(dòng)控制的。

查看變量 autocommit 是否開啟了自動(dòng)提交

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

autocommit 為 ON 表示開啟了自動(dòng)提交。

顯式事務(wù)

事務(wù)需要手動(dòng)開啟、提交或回滾,由開發(fā)者自己控制。

2 種方式手動(dòng)控制事務(wù):

方式 1:

語(yǔ)法:

// 設(shè)置不自動(dòng)提交事務(wù) set autocommit=0;// 執(zhí)行事務(wù)操作 commit|rollback;

示例 1:提交事務(wù)操作,如下:

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:回滾事務(wù)操作,如下:

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)

可以看到上面數(shù)據(jù)回滾了。

我們把 autocommit 還原回去:

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

方式 2:

語(yǔ)法:

start transaction;// 開啟事務(wù) // 執(zhí)行事務(wù)操作 commit|rollback;

示例 1:提交事務(wù)操作,如下:

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 條數(shù)據(jù)。

示例 2:回滾事務(wù)操作,如下:

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)

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

savepoint 關(guān)鍵字

在事務(wù)中我們執(zhí)行了一大批操作,可能我們只想回滾部分?jǐn)?shù)據(jù),怎么做呢?

我們可以將一大批操作分為幾個(gè)部分,然后指定回滾某個(gè)部分。可以使用 savepoin 來(lái)實(shí)現(xiàn),效果如下:

先清除 test1 表數(shù)據(jù):

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

演示 savepoint 效果,認(rèn)真看:

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;// 設(shè)置一個(gè)保存點(diǎn) 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 的語(yǔ)句到當(dāng)前語(yǔ)句之間所有的操作回滾 Query OK, 0 rows affected (0.00 sec)mysql commit;// 提交事務(wù) Query OK, 0 rows affected (0.00 sec)mysql select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)

從上面可以看出,執(zhí)行了 2 次插入操作,最后只插入了 1 條數(shù)據(jù)。

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

只讀事務(wù)

表示在事務(wù)中執(zhí)行的是一些只讀操作,如查詢,但是不會(huì)做 insert、update、delete 操作,數(shù)據(jù)庫(kù)內(nèi)部對(duì)只讀事務(wù)可能會(huì)有一些性能上的優(yōu)化。

用法如下:

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)

只讀事務(wù)中執(zhí)行 delete 會(huì)報(bào)錯(cuò)。

事務(wù)中的一些問(wèn)題(重點(diǎn))

這些問(wèn)題主要是基于數(shù)據(jù)在多個(gè)事務(wù)中的可見(jiàn)性來(lái)說(shuō)的。也是并發(fā)事務(wù)產(chǎn)生的問(wèn)題。

更新丟失

丟失更新就是兩個(gè)不同的事務(wù)(或者 Java 程序線程)在某一時(shí)刻對(duì)同一數(shù)據(jù)進(jìn)行讀取后,先后進(jìn)行修改。導(dǎo)致第一次操作數(shù)據(jù)丟失。

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

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

臟讀

一個(gè)事務(wù)在執(zhí)行的過(guò)程中讀取到了其他事務(wù)還沒(méi)有提交的數(shù)據(jù)。這個(gè)還是比較好理解的。

兩個(gè)事務(wù)同時(shí)操作同一數(shù)據(jù),A 事務(wù)對(duì)該數(shù)據(jù)進(jìn)行了修改還沒(méi)提交的時(shí)候,B 事務(wù)訪問(wèn)了該條事務(wù),并且使用了該數(shù)據(jù),此時(shí) A 事務(wù)回滾,那么 B 事務(wù)讀到的就是臟數(shù)據(jù)。

比如事務(wù) 1,修改了某個(gè)數(shù)據(jù) 事務(wù) 2,剛好訪問(wèn)了事務(wù) 1 修改后的數(shù)據(jù)

此時(shí)事務(wù) 1,回滾了操作 事務(wù) 2,讀到還是回滾前的數(shù)據(jù)

讀已提交

從字面上我們就可以理解,即一個(gè)事務(wù)操作過(guò)程中可以讀取到其他事務(wù)已經(jīng)提交的數(shù)據(jù)。

事務(wù)中的每次讀取操作,讀取到的都是數(shù)據(jù)庫(kù)中其他事務(wù)已提交的最新的數(shù)據(jù)(相當(dāng)于當(dāng)前讀)

不可重復(fù)讀

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

這種情況發(fā)生 在一個(gè)事務(wù)內(nèi)多次讀同一數(shù)據(jù)。A 事務(wù)查詢某條數(shù)據(jù),該事務(wù)未結(jié)束時(shí),B 事務(wù)也訪問(wèn)同一數(shù)據(jù)并進(jìn)行了修改。那么在 A 事務(wù)中的兩 次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的的數(shù)據(jù)可能是不一樣的。

事務(wù) 1,查詢某個(gè)數(shù)據(jù) 事務(wù) 2,修改了某個(gè)數(shù)據(jù),提交

事務(wù) 1,再次查詢這個(gè)數(shù)據(jù)

這樣事務(wù) 1 兩次查詢的數(shù)據(jù)不一樣,稱為不可重復(fù)讀

可重復(fù)讀

一個(gè)事務(wù)操作中對(duì)于一個(gè)讀取操作不管多少次,讀取到的結(jié)果都是一樣的。

幻讀

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

以 mysql 為例:

幻讀現(xiàn)象例子:

可重復(fù)讀模式下,比如有個(gè)用戶表,手機(jī)號(hào)碼為主鍵,有兩個(gè)事物進(jìn)行如下操作

事務(wù) A 操作如下:1、打開事務(wù) 2、查詢號(hào)碼為 X 的記錄,不存在 3、插入號(hào)碼為 X 的數(shù)據(jù),插入報(bào)錯(cuò)(為什么會(huì)報(bào)錯(cuò),先向下看)4、查詢號(hào)碼為 X 的記錄,發(fā)現(xiàn)還是不存在(由于是可重復(fù)讀,所以讀取記錄 X 還是不存在的)

事物 B 操作:在事務(wù) A 第 2 步操作時(shí)插入了一條 X 的記錄,所以會(huì)導(dǎo)致 A 中第 3 步插入報(bào)錯(cuò)(違反了唯一約束)

上面操作對(duì) A 來(lái)說(shuō)就像發(fā)生了幻覺(jué)一樣,明明查詢 X(A 中第二步、第四步)不存在,但卻無(wú)法插入成功

幻讀可以這么理解:事務(wù)中后面的操作(插入號(hào)碼 X)需要上面的讀取操作(查詢號(hào)碼 X 的記錄)提供支持,但讀取操作卻不能支持下面的操作時(shí)產(chǎn)生的錯(cuò)誤,就像發(fā)生了幻覺(jué)一樣。

看第二種解釋:

事務(wù) A 在操作一堆數(shù)據(jù)的時(shí)候,事務(wù) B 插入了一條數(shù)據(jù),A 事務(wù)再次(第二次)查詢,發(fā)現(xiàn)多了一條數(shù)據(jù),像是幻覺(jué)。與不可重復(fù)讀類似,不同的是一個(gè)是修改刪除操作,一個(gè)是新增操作。

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

事務(wù)的隔離級(jí)別

當(dāng)多個(gè)事務(wù)同時(shí)進(jìn)行的時(shí)候,如何確保當(dāng)前事務(wù)中數(shù)據(jù)的正確性,比如 A、B 兩個(gè)事物同時(shí)進(jìn)行的時(shí)候,A 是否可以看到 B 已提交的數(shù)據(jù)或者 B 未提交的數(shù)據(jù),這個(gè)需要依靠事務(wù)的隔離級(jí)別來(lái)保證,不同的隔離級(jí)別中所產(chǎn)生的效果是不一樣的。

事務(wù)隔離級(jí)別主要是解決了上面多個(gè)事務(wù)之間數(shù)據(jù)可見(jiàn)性及數(shù)據(jù)正確性的問(wèn)題。(或者說(shuō)為了解決并發(fā)控制可能產(chǎn)生的異常問(wèn)題,數(shù)據(jù)庫(kù)定義了四種事務(wù)的隔離級(jí)別)

隔離級(jí)別分為 4 種:

讀未提交:READ-UNCOMMITTED

讀已提交:READ-COMMITTED

可重復(fù)讀:REPEATABLE-READ

串行:SERIALIZABLE

上面 4 中隔離級(jí)別越來(lái)越強(qiáng),會(huì)導(dǎo)致數(shù)據(jù)庫(kù)的并發(fā)性也越來(lái)越低。

查看隔離級(jí)別

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

隔離級(jí)別的設(shè)置

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

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

# 隔離級(jí)別設(shè)置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復(fù)讀,SERIALIZABLE 串行 transaction-isolation=READ-UNCOMMITTED

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

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

C:\Windows\system32 net start mysql
mysql 服務(wù)正在啟動(dòng) .mysql 服務(wù)已經(jīng)啟動(dòng)成功。

各種隔離級(jí)別中會(huì)出現(xiàn)的問(wèn)題隔離級(jí)別臟讀可能性不可重復(fù)讀可能性幻讀可能性 READ-UNCOMMITTED 有有有 READ-COMMITTED 無(wú)有有 REPEATABLE-READ 無(wú)無(wú)有 SERIALIZABLE 無(wú)無(wú)無(wú)

下面我們來(lái)演示一下,各種隔離級(jí)別中可見(jiàn)性的問(wèn)題,開啟兩個(gè)窗口,叫做 A、B 窗口,兩個(gè)窗口中登錄 mysql。

READ-UNCOMMITTED:讀未提交

將隔離級(jí)別置為 READ-UNCOMMITTED:

# 隔離級(jí)別設(shè)置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復(fù)讀,SERIALIZABLE 串行 transaction-isolation=READ-UNCOMMITTED

重啟 mysql:

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

C:\Windows\system32 net start mysql
mysql 服務(wù)正在啟動(dòng) .mysql 服務(wù)已經(jīng)啟動(dòng)成功。

查看隔離級(jí)別:

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

先清空 test1 表數(shù)據(jù):

delete from test1;select * from test1;

按時(shí)間順序在 2 個(gè)窗口中執(zhí)行下面操作:

時(shí)間窗口 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:無(wú)數(shù)據(jù),T6-A:有數(shù)據(jù),T6 時(shí)刻 B 還未提交,此時(shí) A 已經(jīng)看到了 B 插入的數(shù)據(jù),說(shuō)明出現(xiàn)了臟讀。

T2-A:無(wú)數(shù)據(jù),T6-A:有數(shù)據(jù),查詢到的結(jié)果不一樣,說(shuō)明不可重復(fù)讀。

結(jié)論:讀未提交情況下,可以讀取到其他事務(wù)還未提交的數(shù)據(jù),多次讀取結(jié)果不一樣,出現(xiàn)了臟讀、不可重復(fù)讀、幻讀

READ-COMMITTED:讀已提交

將隔離級(jí)別置為 READ-COMMITTED

# 隔離級(jí)別設(shè)置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復(fù)讀,SERIALIZABLE 串行 transaction-isolation=READ-COMMITTED

重啟 mysql:

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

C:\Windows\system32 net start mysql
mysql 服務(wù)正在啟動(dòng) .mysql 服務(wù)已經(jīng)啟動(dòng)成功。

查看隔離級(jí)別:

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

先清空 test1 表數(shù)據(jù):

delete from test1;select * from test1;

按時(shí)間順序在 2 個(gè)窗口中執(zhí)行下面操作:

時(shí)間窗口 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:有數(shù)據(jù),T6- A 窗口:無(wú)數(shù)據(jù),A 看不到 B 的數(shù)據(jù),說(shuō)明沒(méi)有臟讀。

T6- A 窗口:無(wú)數(shù)據(jù),T8-A:看到了 B 插入的數(shù)據(jù),此時(shí) B 已經(jīng)提交了,A 看到了 B 已提交的數(shù)據(jù),說(shuō)明可以讀取到已提交的數(shù)據(jù)。

T2-A、T6-A:無(wú)數(shù)據(jù),T8-A:有數(shù)據(jù),多次讀取結(jié)果不一樣,說(shuō)明不可重復(fù)讀。

結(jié)論:讀已提交情況下,無(wú)法讀取到其他事務(wù)還未提交的數(shù)據(jù),可以讀取到其他事務(wù)已經(jīng)提交的數(shù)據(jù),多次讀取結(jié)果不一樣,未出現(xiàn)臟讀,出現(xiàn)了讀已提交、不可重復(fù)讀、幻讀

REPEATABLE-READ:可重復(fù)讀

將隔離級(jí)別置為 REPEATABLE-READ

# 隔離級(jí)別設(shè)置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復(fù)讀,SERIALIZABLE 串行 transaction-isolation=REPEATABLE-READ

重啟 mysql:

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

C:\Windows\system32 net start mysql
mysql 服務(wù)正在啟動(dòng) .mysql 服務(wù)已經(jīng)啟動(dòng)成功。

查看隔離級(jí)別:

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

先清空 test1 表數(shù)據(jù):

delete from test1;select * from test1;

按時(shí)間順序在 2 個(gè)窗口中執(zhí)行下面操作:

時(shí)間窗口 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 窗口:無(wú)數(shù)據(jù),T5-B:有數(shù)據(jù),A 看不到 B 的數(shù)據(jù),說(shuō)明沒(méi)有臟讀。

T8-A:無(wú)數(shù)據(jù),此時(shí) B 已經(jīng)提交了,A 看不到 B 已提交的數(shù)據(jù),A 中 3 次讀的結(jié)果一樣都是沒(méi)有數(shù)據(jù)的,說(shuō)明可重復(fù)讀。

結(jié)論:可重復(fù)讀情況下,未出現(xiàn)臟讀,未讀取到其他事務(wù)已提交的數(shù)據(jù),多次讀取結(jié)果一致,即可重復(fù)讀。

幻讀演示

將隔離級(jí)別置為 REPEATABLE-READ

# 隔離級(jí)別設(shè)置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復(fù)讀,SERIALIZABLE 串行 transaction-isolation=REPEATABLE-READ

重啟 mysql:

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

C:\Windows\system32 net start mysql
mysql 服務(wù)正在啟動(dòng) .mysql 服務(wù)已經(jīng)啟動(dòng)成功。

查看隔離級(jí)別:

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

準(zhǔn)備數(shù)據(jù):

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)

上面我們創(chuàng)建 t_user 表,name 添加了唯一約束,表示 name 不能重復(fù),否則報(bào)錯(cuò)。

按時(shí)間順序在 2 個(gè)窗口中執(zhí)行下面操作:

時(shí)間窗口 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 想插入數(shù)據(jù)路人甲 Java,插入之前先查詢了一下(T5 時(shí)刻)該用戶是否存在,發(fā)現(xiàn)不存在,然后在 T7 時(shí)刻執(zhí)行插入,報(bào)錯(cuò)了,報(bào)數(shù)據(jù)已經(jīng)存在了,因?yàn)?T6 時(shí)刻 B 已經(jīng)插入了路人甲 Java。

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

此時(shí) A 心里想:數(shù)據(jù)明明不存在啊,為什么無(wú)法插入呢?這不是懵逼了么,A 覺(jué)得如同發(fā)生了幻覺(jué)一樣。

SERIALIZABLE:串行

SERIALIZABLE 會(huì)讓并發(fā)的事務(wù)串行執(zhí)行(多個(gè)事務(wù)之間讀寫、寫讀、寫寫會(huì)產(chǎn)生互斥,效果就是串行執(zhí)行,多個(gè)事務(wù)之間的讀讀不會(huì)產(chǎn)生互斥)。

讀寫互斥:事務(wù) A 中先讀取操作,事務(wù) B 發(fā)起寫入操作,事務(wù) A 中的讀取會(huì)導(dǎo)致事務(wù) B 中的寫入處于等待狀態(tài),直到 A 事務(wù)完成為止。

表示我開啟一個(gè)事務(wù),為了保證事務(wù)中不會(huì)出現(xiàn)上面說(shuō)的問(wèn)題(臟讀、不可重復(fù)讀、讀已提交、幻讀),那么我讀取的時(shí)候,其他事務(wù)有修改數(shù)據(jù)的操作需要排隊(duì)等待,等待我讀取完成之后,他們才可以繼續(xù)。

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

這個(gè)類似于 java 中的 java.util.concurrent.lock.ReentrantReadWriteLock 類產(chǎn)生的效果。

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

將隔離級(jí)別置為 SERIALIZABLE

# 隔離級(jí)別設(shè)置,READ-UNCOMMITTED 讀未提交,READ-COMMITTED 讀已提交,REPEATABLE-READ 可重復(fù)讀,SERIALIZABLE 串行 transaction-isolation=SERIALIZABLE

重啟 mysql:

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

C:\Windows\system32 net start mysql
mysql 服務(wù)正在啟動(dòng) .mysql 服務(wù)已經(jīng)啟動(dòng)成功。

查看隔離級(jí)別:

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

先清空 test1 表數(shù)據(jù):

delete from test1;select * from test1;

按時(shí)間順序在 2 個(gè)窗口中執(zhí)行下面操作:

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

按時(shí)間順序運(yùn)行上面的命令,會(huì)發(fā)現(xiàn) T4- B 這樣會(huì)被阻塞,直到 T5- A 執(zhí)行完畢。

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

可以看出來(lái),事務(wù)只能串行執(zhí)行了。串行情況下不存在臟讀、不可重復(fù)讀、幻讀的問(wèn)題了。

小結(jié)

讀未提交 (Read Uncommitted)

讀未提交是隔離級(jí)別最低的一種事務(wù)級(jí)別。在這種隔離級(jí)別下,一個(gè)事務(wù)會(huì)讀到另一個(gè)事務(wù)更新后但未提交的數(shù)據(jù),如果另一個(gè)事務(wù)回滾,那么當(dāng)前事務(wù)讀到的數(shù)據(jù)就是臟數(shù)據(jù),這就是臟讀(Dirty Read)。

讀已提交 (Read Committed)

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

可重復(fù)讀 (Repeatable Read)

在 Repeatable Read 隔離級(jí)別下,一個(gè)事務(wù)可能會(huì)遇到幻讀(Phantom Read)的問(wèn)題。幻讀是指,在一個(gè)事務(wù)中,第一次查詢某條記錄,發(fā)現(xiàn)沒(méi)有,但是,當(dāng)試圖更新這條不存在的記錄時(shí),竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現(xiàn)了。幻讀就是沒(méi)有讀到的記錄,以為不存在,但其實(shí)是可以更新成功的,并且,更新成功后,再次讀取,就出現(xiàn)了。

可串行化 (Serializable)

Serializable 是最嚴(yán)格的隔離級(jí)別。在 Serializable 隔離級(jí)別下,所有事務(wù)按照次序依次執(zhí)行,因此,臟讀、不可重復(fù)讀、幻讀都不會(huì)出現(xiàn)。

雖然 Serializable 隔離級(jí)別下的事務(wù)具有最高的安全性,但是,由于事務(wù)是串行執(zhí)行,所以效率會(huì)大大下降,應(yīng)用程序的性能會(huì)急劇降低。如果沒(méi)有特別重要的情景,一般都不會(huì)使用 Serializable 隔離級(jí)別。

默認(rèn)隔離級(jí)別:如果沒(méi)有指定隔離級(jí)別,數(shù)據(jù)庫(kù)就會(huì)使用默認(rèn)的隔離級(jí)別。在 MySQL 中,如果使用 InnoDB,默認(rèn)的隔離級(jí)別是 Repeatable Read。

關(guān)于隔離級(jí)別的選擇

需要對(duì)各種隔離級(jí)別產(chǎn)生的現(xiàn)象非常了解,然后選擇的時(shí)候才能游刃有余

隔離級(jí)別越高,并發(fā)性也低,比如最高級(jí)別 SERIALIZABLE 會(huì)讓事物串行執(zhí)行,并發(fā)操作變成串行了,會(huì)導(dǎo)致系統(tǒng)性能直接降低。

具體選擇哪種需要結(jié)合具體的業(yè)務(wù)來(lái)選擇。

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

關(guān)于“mysql 事務(wù)的含義是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“mysql 事務(wù)的含義是什么”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注丸趣 TV 行業(yè)資訊頻道。

向 AI 問(wèn)一下細(xì)節(jié)

丸趣 TV 網(wǎng) – 提供最優(yōu)質(zhì)的資源集合!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2024-04-09發(fā)表,共計(jì)15010字。
轉(zhuǎn)載說(shuō)明:除特殊說(shuō)明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請(qǐng)注明出處。
評(píng)論(沒(méi)有評(píng)論)
主站蜘蛛池模板: 盐山县| 清丰县| 大化| 那坡县| 嫩江县| 湄潭县| 阜阳市| 尚志市| 延吉市| 常宁市| 大安市| 兰溪市| 清丰县| 柘城县| 喀喇沁旗| 稷山县| 安顺市| 民和| 茶陵县| 陇南市| 长春市| 沂水县| 林口县| 焦作市| 通江县| 贵德县| 宜兰市| 塔河县| 车险| 固阳县| 建德市| 涡阳县| 乳山市| 镇江市| 开封县| 兰坪| 策勒县| 蒙城县| 南开区| 防城港市| 色达县|