真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

MySQL數(shù)據(jù)庫高級(七)——事務(wù)和鎖

MySQL數(shù)據(jù)庫高級(七)——事務(wù)和鎖

一、事務(wù)簡介

1、事務(wù)簡介

事務(wù)(Transaction) 是指作為單個邏輯工作單元執(zhí)行的一系列操作。

公司主營業(yè)務(wù):成都網(wǎng)站建設(shè)、做網(wǎng)站、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)推出臨滄免費(fèi)做網(wǎng)站回饋大家。

2、事務(wù)的特性

A、原子性(Atomicity)
表示組成一個事務(wù)的多個數(shù)據(jù)庫操作是一個不可分隔的原子單元,只有所有的操作執(zhí)行成功,整個事務(wù)才提交,事務(wù)中任何一個數(shù)據(jù)庫操作失敗,已經(jīng)執(zhí)行的任何操作都必須撤銷,讓數(shù)據(jù)庫返回到初始狀態(tài)。
B、一致性(Consistency)
事務(wù)操作成功后,數(shù)據(jù)庫所處的狀態(tài)和它的業(yè)務(wù)規(guī)則是一致的,即數(shù)據(jù)不會被破壞。
C、隔離性(Isolation)
在并發(fā)數(shù)據(jù)操作時,不同的事務(wù)擁有各自數(shù)據(jù)空間,它們的操作不會對對方產(chǎn)生干擾。數(shù)據(jù)庫規(guī)定了多種事務(wù)隔離級別,不同隔離級別對應(yīng)不同的干擾程度,隔離級別越高,數(shù)據(jù)一致性越好,但并發(fā)性越弱。
D、持久性(Durabiliy)
一旦事務(wù)提交成功后,事務(wù)中所有的數(shù)據(jù)操作都必須被持久化到數(shù)據(jù)庫中,即使提交事務(wù)后,數(shù)據(jù)庫馬上崩潰,在數(shù)據(jù)庫重啟時,也必須能保證能夠通過某種機(jī)制恢復(fù)數(shù)據(jù)。

3、事務(wù)類型

A、自動提交事務(wù)
系統(tǒng)默認(rèn)每個TRANSACT-SQL命令都是一個事務(wù)處理,由系統(tǒng)自動開始并提交。
B、隱式事務(wù)
不需要顯示開始事務(wù),需要顯示提交,隱式事務(wù)是任何單獨(dú)的INSERT、UPDATE 或者DELETE語句構(gòu)成。當(dāng)有大量的DDL和DML命令執(zhí)行時會自動開始,并一直保持到用戶明確提交為止。
SHOW VARIABLES 查看變量。
SET AUTOCOMMIT=0,關(guān)閉自動提交功能。
需要顯示提交或者回滾。

update tablename set sname='孫悟空' where studentid='000000000000003';
commit;


rollback;
C、顯示事務(wù)
顯示事務(wù)是用戶自定義事務(wù),以START TRANSACTION(事務(wù)開始)開頭,以 COMMIT(事務(wù)提交)或者 ROLLBACK(回滾事務(wù))語句結(jié)束。

start transaction 
update tablename set sname='孫悟空' where studentid='000000000000003';
commit


rollback
D、分布式事務(wù)
跨越多個服務(wù)器的事務(wù)稱為分布式事務(wù)。從MySQL5.03開始支持分布式事務(wù)。

4、事務(wù)控制

A、開始事務(wù)
標(biāo)記一個顯式事務(wù)的開始點(diǎn),即事務(wù)開始。其語法如下:
START { TRAN | TRANSACTION }
B、提交事務(wù)
標(biāo)記一個成功的隱性事務(wù)或顯式事務(wù)的結(jié)束,即事務(wù)提交。其語法如下:
COMMIT
C、回滾事務(wù)
將顯式事務(wù)或隱性事務(wù)回滾到事務(wù)的起點(diǎn)或事務(wù)內(nèi)的某個保存點(diǎn)。其語法如下:
ROLLBACK
D、事務(wù)設(shè)置
SET AUTOCOMMIT 可以修改當(dāng)前連接事務(wù)提交方式。
SET AUTOCOMMIT=0,則需要明確的命令進(jìn)行提交或者回滾。

5、事務(wù)并發(fā)帶來的問題

臟讀(Dirty Read)是指某個事務(wù)(A)讀取另外事務(wù)(B)尚未提交的更改數(shù)據(jù),并在讀取的數(shù)據(jù)的基礎(chǔ)上操作。如果恰巧 B事務(wù)回滾,那么 A事務(wù)讀到的數(shù)據(jù)根本是不被承認(rèn)的。
不可重復(fù)讀(Unrepeatable Read)是指A事務(wù)讀取了B事務(wù)已經(jīng)提交的更改數(shù)據(jù)。
幻象讀(Phantom Read)
A事務(wù)讀取B事務(wù)提交的新增數(shù)據(jù),這時A事務(wù)將出現(xiàn)幻象讀的問題。
第一類丟失更新
A事務(wù)撤銷時,把已經(jīng)提交的B事務(wù)的更新數(shù)據(jù)覆蓋。
第二類丟失更新
A事務(wù)覆蓋B事務(wù)已經(jīng)提交的數(shù)據(jù),造成B事務(wù)所做操作丟失。

二、事務(wù)隔離級別

1、事務(wù)隔離級別簡介

SQL標(biāo)準(zhǔn)定義了4類隔離級別,包括了一些具體規(guī)則,用來限定事務(wù)內(nèi)外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的并發(fā)處理,并擁有更低的系統(tǒng)開銷。
Read Uncommitted(讀取未提交內(nèi)容)
本隔離級別,事務(wù)可以讀取其他未提交事務(wù)的執(zhí)行結(jié)果。讀取未提交的數(shù)據(jù),也被稱之為臟讀(Dirty Read)。
Read Committed(讀取提交內(nèi)容)
大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認(rèn)隔離級別(但不是MySQL默認(rèn)的)。事務(wù)只能讀取其他事務(wù)已經(jīng)提交的執(zhí)行結(jié)果。本隔離級別支持所謂的不可重復(fù)讀(Nonrepeatable Read),因為同一事務(wù)的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結(jié)果。
Repeatable Read(可重讀)
MySQL默認(rèn)的事務(wù)隔離級別,會給查詢的記錄做快照,直到事務(wù)結(jié)束。確保同一事務(wù)的多個實例在并發(fā)讀取數(shù)據(jù)時,會看到同樣的數(shù)據(jù)行,會導(dǎo)致幻讀(Phantom Read)?;米x指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時,另一個事務(wù)又在該范圍內(nèi)插入了新行,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時,會發(fā)現(xiàn)有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本并發(fā)控制(MVCC,Multiversion Concurrency Control)機(jī)制解決了幻讀問題。
Serializable(可串行化)
最高的隔離級別,對同一條記錄讀和修改的多個事務(wù)只能結(jié)束一個,才能開始下一個。
通過強(qiáng)制事務(wù)排序,使之不可能相互沖突,從而解決幻讀問題。在每個讀的數(shù)據(jù)行上加上共享鎖,可能導(dǎo)致大量的超時現(xiàn)象和鎖競爭。

2、事務(wù)隔離級別設(shè)置

用戶可以用SET TRANSACTION語句改變單個會話或者所有新進(jìn)連接的隔離級別。語法如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
默認(rèn)的行為(不帶session和global)是為下一個(未開始)事務(wù)設(shè)置隔離級別。如果使用GLOBAL關(guān)鍵字,語句在全局對新開始創(chuàng)建的所有新連接設(shè)置默認(rèn)事務(wù)級別,需要SUPER權(quán)限。使用SESSION關(guān)鍵字為將來在當(dāng)前連接上執(zhí)行的事務(wù)設(shè)置默認(rèn)事務(wù)級別。 任何客戶端都能自由改變會話隔離級別,或者為下一個事務(wù)設(shè)置隔離級別。
查詢?nèi)趾蜁捠聞?wù)隔離級別:

SELECT @@global.tx_isolation; 
SELECT @@session.tx_isolation; 
SELECT @@tx_isolation;

通過mySQL配置文件修改全局事務(wù)隔離級別,設(shè)置全局會話默認(rèn)事務(wù)隔離級別。

[mysqld]
xxxxxxx
transaction-isolation=read-committed

重啟mySQL服務(wù),生效。
設(shè)置當(dāng)前會隔離級別

SET  SESSION  TRANSACTION ISOLATION LEVEL  READ UNCOMMITTED
SET  SESSION  TRANSACTION ISOLATION LEVEL  READ COMMITTED
SET  SESSION  TRANSACTION ISOLATION LEVEL  REPEATABLE READ
SET  SESSION  TRANSACTION ISOLATION LEVEL  SERIALIZABLE

三、事務(wù)隔離級別驗證

1、不同會話的隔離級別

不同會話的事務(wù)隔離級別不同
在會話1終端查看當(dāng)前會話的事務(wù)隔離級別
select @@tx_isolation
查詢結(jié)果為:可重復(fù)讀REPEATABLE-READ
設(shè)置當(dāng)前會話事務(wù)隔離級別為READ UNCOMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
打開另一個SQL Manager終端作為會話2,查看當(dāng)前會話的事務(wù)隔離級別
select @@tx_isolation
查詢結(jié)果為:可重復(fù)讀REPEATABLE-READ
創(chuàng)建一張表,含ID、姓名、年齡字段,用于驗證不同的事務(wù)隔離級別。

CREATE TABLE ta
(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(10),
age INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into ta values(1, '孫悟空', 500);
insert into ta values(2, '唐僧', 30);

注:由于本人SQL Manager Lite客戶端的事務(wù)回滾機(jī)制失效,以下實驗使用Navicat for MySQL客戶端。

2、驗證READ UNCOMMITTED隔離級別

打開一個會話1,設(shè)置事務(wù)隔離級別為READ UNCOMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
打開會話2,開始一個事務(wù),更新ID為1的記錄的age為1000。

start TRANSACTION;
update ta set age=1000 where id =1;

在會話1查看ta表中ID為1的信息,age已經(jīng)為1000。
select * from ta;
會話1的事務(wù)隔離級別允許讀取未提交的數(shù)據(jù)。
在會話2回滾事務(wù)
ROLLBACK;
會話1和會話2查詢ta表中ID為1的記錄,age為500

3、驗證READ COMMITTED隔離級別

打開一個會話1,設(shè)置事務(wù)隔離級別為READ COMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
打開會話2,開始一個事務(wù),更新ID為1的記錄的age為5000。

start TRANSACTION;
update ta set age=5000 where id =1;

在會話1查看ta表中ID為1的信息,age為500。
select * from ta;
會話1的事務(wù)隔離級別不允許讀取未提交的數(shù)據(jù)。
在會話2提交事務(wù)
COMMIT;
會話1查詢ta表中ID為1的記錄,age為5000

4、驗證REPEATABLE READ隔離級別

打開一個會話1,設(shè)置事務(wù)隔離級別為REPEATABLE READ
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
在會話1,開始一個事務(wù),查詢ID為1的記錄的age為5000。

start TRANSACTION;
SELECT * FROM ta where id =1;

在會話2更新ta表中ID為1的信息,age為1000。
UPDATE ta SET age=1000 WHERE id=1;
在會話2查看ta表中ID為1的信息,age已經(jīng)為1000。
select * from ta WHERE id=1;
在會話1再次查看ta表中ID為1的信息,age仍舊為5000。
select * from ta WHERE id=1;
在會話1提交事務(wù)
COMMIT;
會話1查詢ta表中ID為1的記錄,age已經(jīng)為1000。

5、驗證SERIALIZABLE隔離級別

打開一個會話1,設(shè)置事務(wù)隔離級別為SERIALIZABLE
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE
打開會話2,開始一個事務(wù),更新ID為1的記錄的age為5000。

start TRANSACTION;
update ta set age=5000 where id =1;

在會話1開始一個事務(wù),查看ta表中ID為1的信息,會話1處于等待狀態(tài)。

start TRANSACTION;
select * from ta;

在會話2提交事務(wù)后,
COMMIT;
會話1查詢SQL執(zhí)行完畢,結(jié)果為5000。

四、鎖

1、鎖簡介

數(shù)據(jù)庫中的鎖是指一種軟件機(jī)制,用來控制防止某個用戶(進(jìn)程會話)在已經(jīng)占用了某種數(shù)據(jù)資源時,其他用戶做出影響本用戶數(shù)據(jù)操作或?qū)е聰?shù)據(jù)非完整性和非一致性問題發(fā)生的手段。

2、鎖的級別

按照鎖級別劃分,鎖可分為共享鎖、排他鎖。
A、共享鎖(讀鎖)
針對同一塊數(shù)據(jù),多個讀操作可以同時進(jìn)行而不會互相影響。
共享鎖只針對UPDATE時候加鎖,在未對UPDATE操作提交之前,其他事務(wù)只能夠獲取最新的記錄但不能夠UPDATE操作。
B、排他鎖(寫鎖)
當(dāng)前寫操作沒有完成前,阻斷其他寫鎖和讀鎖。

3、鎖的粒度

按鎖的粒度劃分,鎖可分為表級鎖、行級鎖、頁級鎖。
A、行級鎖
開銷大,加鎖慢,會出現(xiàn)死鎖,鎖定力度最小,發(fā)生鎖沖突的概率最低,并發(fā)度高。
B、表級鎖
開銷小,加鎖快,不會出現(xiàn)死鎖,鎖定力度大,發(fā)生沖突所的概率高,并發(fā)度低。
C、頁面鎖
開銷和加鎖時間介于表鎖和行鎖之間,會出現(xiàn)死鎖,鎖定力度介于表和行行級鎖之間,并發(fā)度一般。

4、MySQL存儲引擎和鎖機(jī)制

MySQL的鎖機(jī)制比較簡單,最顯著的特點(diǎn)是不同的存儲引擎支持不同的鎖機(jī)制。
MyISAM和MEMORY存儲引擎采用表級鎖。
InnoDB支持行級鎖、表級鎖,默認(rèn)情況采用行級鎖。

五、表級鎖

1、表級鎖簡介

MyISAM存儲引擎和InnoDB存儲引擎都支持表級鎖。
MyISAM存儲引擎支持表級鎖,為了保證數(shù)據(jù)的一致性,更改數(shù)據(jù)時,防止其他人更改數(shù)據(jù),可以人工添加表級鎖。可以使用命令對數(shù)據(jù)庫的表枷鎖,使用命令對數(shù)據(jù)庫的表解鎖。
給表加鎖的命令Lock Tables,給表解鎖的命令Unlock Tables
MyISAM引擎在用戶讀數(shù)據(jù)自動加READ鎖,更改數(shù)據(jù)自動加WRITE鎖。使用lock Tables和Unlock Tables顯式加鎖和解鎖。

2、添加表級讀鎖

打開會話1,創(chuàng)建表

CREATE TABLE tc
(
id INT,
name VARCHAR(10),
age INT
)ENGINE=MyISAM DEFAULT CHARSET=utf8;

插入兩條記錄:

insert into tc values(1, '孫悟空', 500);
insert into tc values(3, '豬八戒', 100);

對表加READ鎖
lock tables tc read;
加鎖后只可以查詢已經(jīng)加鎖的表,
select * from tc;
查詢沒有加鎖的表將失敗
select * from ta;
打開會話2,對已經(jīng)加鎖的表進(jìn)行查詢,成功。
select * from tc;
對加鎖的表tc進(jìn)行更新操作,將失敗
update tc set age=100 where id=1;
會話1中使用LOCK TABLE命令給表加了讀鎖,會話1可以查詢鎖定表中的記錄,但更新或訪問其他表都會提示錯誤;會話2可以查詢表中的記錄,但更新就會出現(xiàn)鎖等待。
在會話1對表進(jìn)行解鎖,會話2的更新操作成功。
unlock tables;
在會話1,再次鎖定表tc,后面帶local參數(shù)。
lock tables tc read local;
Local參數(shù)允許在表尾并發(fā)插入,只鎖定表中當(dāng)前記錄,其他會話可以插入新的記錄
在會話2插入一條記錄
insert into tc values(2, '唐僧', 20);
在會話1查看tc表的記錄,無插入記錄
select * from tc;

3、設(shè)置表級鎖并發(fā)性

READ鎖是共享鎖,不影響其他會話的讀取,但不能更新已經(jīng)加READ鎖的數(shù)據(jù)。MyISAM表的讀寫是串行的,但是總體而言的,在一定條件下,MyISAM表也支持查詢和插入操作的并發(fā)進(jìn)行。
MyISAM存儲引擎有一個系統(tǒng)變量concurrent_insert,用以控制其并發(fā)插入的行為,其值分別可以為0、1或2。
0:不允許并發(fā)操作
1:如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個進(jìn)程讀表的同時,另一個進(jìn)程從表尾插入記錄,是MySQL的默認(rèn)設(shè)置。
2:無論MyISAM表中有沒有空洞,都允許在表尾并發(fā)插入記錄。
在MySQL配置文件添加,concurrent_insert=2,重啟mySQL服務(wù)設(shè)置生效。

4、驗證表級鎖的并發(fā)性

設(shè)置concurrent_insert為0
在會話1對表tc加鎖
lock tables tc read local;
在會話2插入一條記錄,此時tc表被鎖定,進(jìn)入等待
insert into tc values(4, '沙悟凈', 30);
在會話1解鎖表tc,此時會話2插入成功
unlock tables;

設(shè)置concurrent_insert為1
在會話1刪除ID為3的記錄
delete from tc where id=3;
在會話1對表tc加鎖
lock tables tc read local;
在會話2插入一條記錄,此時tc表被鎖定,并且表中有空洞,進(jìn)入等待
insert into tc values(5, '白骨精', 1000);
在會話1解鎖表tc,此時會話2插入成功,此時表中已經(jīng)沒有空洞
unlock tables;
在會話1對表tc加鎖
lock tables tc read local;
在會話2插入一條記錄,插入成功,支持有條件并發(fā)插入
insert into tc values(6, '白骨精', 1000);
在會話1解鎖表tc
unlock tables;

設(shè)置concurrent_insert為2
在會話1刪除ID為5的記錄,創(chuàng)造一個空洞
delete from tc where id=5;
在會話1對表tc加鎖
lock tables tc read local;
在會話2插入一條記錄,插入成功,支持無條件并發(fā)插入
insert into tc values(7, '蜘蛛精', 1000);
在會話1解鎖表tc
unlock tables;

5、添加表級寫鎖

添加表級寫鎖語法如下:
LOCK TABLES tablename WRITE;
不允許其他會話查詢、修改、插入記錄。

六、行級鎖

1、行級鎖簡介

InnoDB存儲引擎實現(xiàn)的是基于多版本的并發(fā)控制協(xié)議——MVCC (Multi-Version Concurrency Control)。MVCC的優(yōu)點(diǎn)是讀不加鎖,讀寫不沖突。在讀多寫少的OLTP應(yīng)用中,讀寫不沖突是非常重要的,極大的增加了系統(tǒng)的并發(fā)性能。
在MVCC并發(fā)控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當(dāng)前讀 (current read)。
快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。
當(dāng)前讀,讀取的是記錄的最新版本,并且當(dāng)前讀返回的記錄都會加上鎖,保證其他事務(wù)不會再并發(fā)修改。事務(wù)加鎖,是針對所操作的行,對其他行不進(jìn)行加鎖處理。
快照讀:簡單的SELECT操作,屬于快照讀,不加鎖。
select * from table where ?;
當(dāng)前讀:特殊的讀操作,INSERT/UPDATE/DELETE,屬于當(dāng)前讀,需要加鎖。

select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;

以上SQL語句屬于當(dāng)前讀,讀取記錄的最新版本。并且,讀取之后,還需要保證其他并發(fā)事務(wù)不能修改當(dāng)前記錄,對讀取記錄加鎖。其中,除了第一條語句,對讀取記錄加S鎖 (共享鎖)外,其他的操作,都加的是X鎖 (排它鎖)。

2、驗證快照讀

打開會話1,創(chuàng)建一個表,含ID、姓名、年齡

CREATE TABLE td
(
id INT ,
name VARCHAR(10),
age INT
)ENGINE=innoDB DEFAULT CHARSET=utf8;

在插入兩條記錄

insert into td values(1, '孫悟空', 500);
insert into td values(2, '豬八戒', 100);

在會話1開始事務(wù)
start transaction;
在會話1查詢ID位1的記錄信息
select * from td where id =1;
打開會話2,更新ID為1的age為1000
update td set age=1000 where id=1;
在會話2查看ID為1的age已經(jīng)更新為1000。
select * from td where id =1;
在會話1查看ID為1的age,仍然為500。
select * from td where id =1;
在會話1提交事務(wù)
COMMIT;
在會話1查看ID為1的age,已經(jīng)為1000。

3、驗證當(dāng)前讀

在會話1開始事務(wù)
start transaction;
在會話1給select語句添加共享鎖。
select * from td where id=1 lock in share mode;
在會話2,更新ID為1的age的值為100,進(jìn)入鎖等待
update td set age=100 where id=1;
在會話1提交事務(wù)
COMMIT;
會話2的更新操作成功。

4、驗證事務(wù)給記錄加鎖

在會話1開始事務(wù)
start transaction;
在會話1更新ID為1的age的值為500。
update td set age=500 where id=1;
在會話2開始事務(wù)
start transaction;
在會話2更新ID為2的age的值為1000,此時進(jìn)入鎖等待
update td set age=1000 where id=2;
td表沒有指定主鍵,事務(wù)不支持行級鎖。會話1的事務(wù)給整張表加了鎖。
在會話1提交事務(wù),此時會話2的修改成功
COMMIT;
在會話2提交事務(wù),解除對表的鎖定
COMMIT;
在會話1,給表的ID增加主鍵
alter table td add primary key(id);
在會話1開始事務(wù)
start transaction;
在會話1更新ID為1的age的值為5000
update td set age=5000 where id=1;
在會話2上開始事務(wù)
start transaction;
在會話2上修改ID為2的get的值為10000,更新成功,說明會話1只鎖定了ID為1的行。
update td set age=10000 where id=2;
在會話2上更新ID是1的age值為100,出現(xiàn)等待。因為會話1給ID為1的行添加了獨(dú)占鎖。
update td set age=5000 where id=1;
在會話1提交事務(wù)
COMMIT;
在會話2提交事務(wù)
COMMIT;
在會話1查詢,會話1和會話2對age列的修改都生效
select * from td;

5、死鎖的產(chǎn)生

A事務(wù)添加共享鎖后,B事務(wù)也可以添加共享鎖。A事務(wù)UPDATE鎖定記錄,處于等待中,于此同時B事務(wù)也UPDATE更新鎖定的記錄,就產(chǎn)生死鎖。
在會話1開始事務(wù)
start transaction;
在會話1查詢ID是1的記錄,并添加共享鎖。
select * from td where id=1 lock in share mode;
在會話2開始事務(wù)
start transaction;
在會話2查詢ID是1的記錄,并添加共享鎖。
select * from td where id=1 lock in share mode;
在會話1更新ID為1的age值為,等待會話2釋放共享鎖
update td set age=200 where id=1;
在會話2更新ID為1的age為,會話2發(fā)現(xiàn)死鎖,回滾事務(wù)。
update td set age=200 where id=1;
在會話1提交事務(wù)
COMMIT;

七、事務(wù)實例

事務(wù)提交還是回滾,可以在事務(wù)結(jié)束處判斷是否出現(xiàn)錯誤,如果出現(xiàn),回滾。如果沒有錯誤,提交事務(wù)。
使用自定義條件來決定事務(wù)是提交還是回滾。

1、由錯誤決定事務(wù)提交或回滾

在存儲過程中使用事務(wù),在事務(wù)的末尾判斷是否有錯誤,插入失敗,則回滾事務(wù)。
創(chuàng)建兩張表,存儲ID、姓名、年齡,創(chuàng)建存儲過程將A表的指定ID的記錄轉(zhuǎn)移到B表。

CREATE TABLE ta
(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(10),
age INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into ta values(1, '孫悟空', 500);
insert into ta values(2, '唐僧', 30);

CREATE TABLE tb
(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(10),
age INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into tb values(1, '孫悟空', 500);
insert into tb values(3, '豬八戒', 100);
CREATE PROCEDURE move(num INT)
BEGIN
DECLARE errorinfo INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET errorinfo=1;
START TRANSACTION;
INSERT INTO tb SELECT * FROM ta WHERE id=num;
DELETE FROM ta WHERE id=num;
IF errorinfo=1 
   THEN ROLLBACK;
ELSE
   COMMIT;
END IF;
END

將ID為2的記錄從A表轉(zhuǎn)移到B表
call move(2);

2、由自定義條件決定事務(wù)提交或回滾

創(chuàng)建兩個表,每個表含賬戶、姓名、余額信息,創(chuàng)建一個存儲過程,從A表中的一個賬戶轉(zhuǎn)賬一定金額到B表的一個賬戶,如果轉(zhuǎn)出賬戶的余額不足,則回滾,否則提交。

create table accountA
(
account INT PRIMARY KEY NOT NULL,
name VARCHAR(10),
balance DOUBLE
)ENGINE=innoDB default CHARSET=utf8;

insert into accountA VALUES(1, '孫悟空', 10000);
insert into accountA VALUES(2, '唐僧', 20000);
create table accountB
(
account INT PRIMARY KEY NOT NULL,
name VARCHAR(10),
balance DOUBLE
)ENGINE=innoDB default CHARSET=utf8;

insert into accountB VALUES(1, '孫悟空', 10000);
insert into accountB VALUES(2, '唐僧', 20000);
CREATE PROCEDURE transfer(fromaccout INT,toaccount INT, num DOUBLE)
BEGIN
DECLARE m DOUBLE;
START TRANSACTION;
UPDATE accountB SET balance=balance + num WHERE account=toaccount;
UPDATE accountA SET balance=balance - num WHERE account=fromaccout;
SELECT balance INTO m from accountA WHERE account=fromaccout;
IF m < 0
   THEN ROLLBACK;
ELSE 
   COMMIT;
END IF;
END

從A表的賬戶2轉(zhuǎn)出25000元到B表的賬戶2。
call transfer(2,2,25000);
此時A表的余額不足,回滾


網(wǎng)頁題目:MySQL數(shù)據(jù)庫高級(七)——事務(wù)和鎖
瀏覽地址:http://weahome.cn/article/pgjcpd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部