国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

MySQL 事務(wù)的基礎(chǔ)知識(shí)

這篇具有很好參考價(jià)值的文章主要介紹了MySQL 事務(wù)的基礎(chǔ)知識(shí)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

事務(wù)的基礎(chǔ)知識(shí)

1. 數(shù)據(jù)庫(kù)事務(wù)概述

事務(wù)是數(shù)據(jù)庫(kù)區(qū)別于文件系統(tǒng)的重要特性之一,當(dāng)我們有了事務(wù)就會(huì)讓數(shù)據(jù)庫(kù)中的數(shù)據(jù)始終保持 一致性,同時(shí)我們還能通過(guò)事務(wù)的機(jī)制 恢復(fù)到某個(gè)時(shí)間地點(diǎn)的數(shù)據(jù),這樣可以保證已提交到數(shù)據(jù)庫(kù)的修改不會(huì)因?yàn)橄到y(tǒng)崩潰而丟失。

1.1 存儲(chǔ)引擎的支持情況

查詢當(dāng)前 MySQL 支持的存儲(chǔ)引擎

show engines;
Engine Support Comment Transactions XA Savepoints
MEMORY YES Hash based, stored in memory, useful for temporary tables NO NO NO
MRG_MYISAM YES Collection of identical MyISAM tables NO NO NO
CSV YES CSV storage engine NO NO NO
FEDERATED NO Federated MySQL storage engine
PERFORMANCE_SCHEMA YES Performance Schema NO NO NO
MyISAM YES MyISAM storage engine NO NO NO
InnoDB DEFAULT Supports transactions, row-level locking, and foreign keys支持事務(wù)、行級(jí)鎖定和外鍵 YES YES YES
BLACKHOLE YES /dev/null storage engine (anything you write to it disappears) NO NO NO
ARCHIVE YES Archive storage engine NO NO NO

只有 InnoDB 存儲(chǔ)引擎是支持事務(wù)的

1.2 基本概念

事務(wù):一組邏輯操作單元,使數(shù)據(jù)從一種狀態(tài)變換到另一種狀態(tài)。

事務(wù)處理的原則:保證所有事務(wù)都作為 一個(gè)工作單元 來(lái)執(zhí)行,即使出現(xiàn)了故障,都不能改變這種執(zhí)行方式。當(dāng)在一個(gè)事務(wù)中執(zhí)行多個(gè)操作時(shí),要么所有的事務(wù)都被提交(commit),那么這些修改就 永遠(yuǎn) 地保持下來(lái);要么 放棄 所做的所有 修改,整個(gè)事務(wù)回滾(rollback)到最初狀態(tài)。

例如:賬戶轉(zhuǎn)賬(aa 向 bb 轉(zhuǎn)賬 100 元)

# aa 減 100
update account set money = money - 100 where name = 'AA';
# bb 加 100
update account set money = money + 100 where name = 'BB';

以上的操作就是 "一組邏輯操作單元" ,在邏輯上(業(yè)務(wù)中)是不可分割的。

注意如果在為 bb 加錢時(shí),出現(xiàn)故障或者錯(cuò)誤,那么將放棄 aa 減錢的操作,將錢退回給 aa。

1.3 事務(wù)的 ACIC 特性

1.3.1 原子性(atomicity)

原子性是指事務(wù)是 一個(gè)不可分割的工作單位,要么全部提交,要么全部失敗回滾

即要么轉(zhuǎn)賬成功,要么轉(zhuǎn)賬失敗,是不存在中間的狀態(tài)。如果無(wú)法保證原子性會(huì)怎么樣?就會(huì)出現(xiàn)數(shù)據(jù)不一致的情形,a賬戶減去100元,而b賬戶增加100元操作失敗,系統(tǒng)將無(wú)故丟失100元。

1.3.2 一致性(consistency)

(建議參考 Wikipedia 對(duì) 一致性(consistency)的闡述)

根據(jù)定義,一致性是事務(wù)執(zhí)行前后,數(shù)據(jù)從一個(gè) 合法性狀態(tài) 變換另外一個(gè) 合法性狀態(tài) 。這種狀態(tài)是 語(yǔ)義上 的而不是語(yǔ)法上的,根據(jù)具體的業(yè)務(wù)有關(guān)

那什么是合法的數(shù)據(jù)狀態(tài)呢?

滿足 預(yù)定的約束 的狀態(tài)就叫做合法的狀態(tài)。通俗一點(diǎn),這狀態(tài)是由我們自己來(lái)定義的(比如滿足現(xiàn)實(shí)世界中的約束)滿足這個(gè)狀態(tài),數(shù)據(jù)就是一致性的,不滿足這個(gè)狀態(tài),數(shù)據(jù)就是不一致的!,如果事務(wù)中的某個(gè)操作失敗了,系統(tǒng)就會(huì)自動(dòng)撤銷當(dāng)前正在執(zhí)行的事務(wù),返回到事務(wù)操作之前的狀態(tài)。

舉例1:賬戶的余額必須 >=0

a賬戶有200元,轉(zhuǎn)賬300元出去,此時(shí)賬戶余額為-100元。此時(shí)數(shù)據(jù)就是不一致的。因?yàn)槎x了余額必須 >=0 狀態(tài)(規(guī)則)。

舉例2:不管怎么操作,兩個(gè)賬戶的總余額必須不變

a賬戶200元,轉(zhuǎn)賬50元給b賬戶,a賬戶的錢扣了,但是b賬戶因?yàn)楦鞣N意外,余額并沒(méi)有增加,此時(shí)數(shù)據(jù)就是不一致的、因?yàn)槎x了a和b的總余額必須不變的狀態(tài)(規(guī)則)

舉例3:唯一性約束

在數(shù)據(jù)表中我們將 姓名 字段設(shè)置為 唯一性約束,這時(shí)當(dāng)事務(wù)進(jìn)行提交或者事務(wù)發(fā)生回滾的時(shí)候,如果數(shù)據(jù)表中的姓名不唯一,就破壞了事務(wù)的一致性要求。

1.3.3 隔離性(isolation)

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

如果無(wú)法保證隔離性會(huì)怎么樣?

假設(shè)a賬戶有200元,b賬戶0元。a賬戶往b賬戶轉(zhuǎn)賬兩次,每次金額為50元,分別在兩個(gè)事務(wù)中執(zhí)行。如果無(wú)法保證隔離性,就可能會(huì)出現(xiàn) 數(shù)據(jù)不一致 的情形:

update accounts set money = money - 50 where name = 'aa';

update accounts set money = money + 50 where name = 'bb';

MySQL 事務(wù)的基礎(chǔ)知識(shí)

該行為就造成了 "臟寫"。

1.3.4 持久性(durability)

持久性是指一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫(kù)中的數(shù)據(jù)的改變就是 永久性的(寫入磁盤了),接下來(lái)的其他操作和數(shù)據(jù)庫(kù)故障不應(yīng)該對(duì)其有任何影響。

持久性是通過(guò) 事務(wù)日志 來(lái)保證的。日志包括了 重做日志回滾日志。

當(dāng)我們通過(guò)事務(wù)對(duì)數(shù)據(jù)進(jìn)行修改的時(shí)候,首先會(huì)將數(shù)據(jù)庫(kù)的變化信息記錄到 重做日志 中,然后再對(duì)數(shù)據(jù)庫(kù)中對(duì)應(yīng)的行進(jìn)行修改。這樣做的好處是,即使數(shù)據(jù)庫(kù)系統(tǒng)崩潰,數(shù)據(jù)庫(kù)重啟后也能找到?jīng)]有更新到數(shù)據(jù)庫(kù)系統(tǒng)中的 重做日志,重新執(zhí)行,從而使事務(wù)具有持久性。

1.3.5 總結(jié) - 重要概念

ACID 是事務(wù)的四大特性,在這四個(gè)特性中 原子性是 "基礎(chǔ)",隔離性是 "手段",一致性是 "約束條件",而持久性是 "目的"。

數(shù)據(jù)庫(kù)事務(wù),其實(shí)就是數(shù)據(jù)庫(kù)設(shè)計(jì)者為了方便起見(jiàn),把需要保證 原子性,隔離性,一致性 和 持久性? 的一個(gè)或多個(gè)數(shù)據(jù)庫(kù)操作?稱為一個(gè)事務(wù)。

1.4 事務(wù)的狀態(tài)

我們現(xiàn)在知道 事務(wù) 是一個(gè)抽象的概念,它其實(shí)對(duì)應(yīng)著 一個(gè)或多個(gè)數(shù)據(jù)庫(kù)操作(dml),MySQL 根據(jù)這些操作所執(zhí)行的不同階段把 事務(wù) 大致劃分成幾個(gè)狀態(tài):

  • 活動(dòng)的(active)

事務(wù)對(duì)應(yīng)的 數(shù)據(jù)庫(kù)操作正在執(zhí)行過(guò)程中時(shí),我們就說(shuō)該事務(wù)處在 活動(dòng)的 狀態(tài)。

  • 部分提交的(partially committed)

當(dāng)事務(wù)中的 最后一個(gè)操作執(zhí)行完成,但由于操作都在內(nèi)存中執(zhí)行,所造成的影響并 沒(méi)有刷新到磁盤 時(shí),我們就說(shuō)該事務(wù)處在 部分提交的 狀態(tài)。(在刷盤之前

  • 失敗的(failed)

當(dāng)事務(wù)處在 活動(dòng)的 或者 部分提交的 狀態(tài)時(shí),可能遇到了某些錯(cuò)誤(數(shù)據(jù)庫(kù)自身的錯(cuò)誤,操作系統(tǒng)錯(cuò)誤或者直接斷電等)而無(wú)法繼續(xù)執(zhí)行,或者人為的停止當(dāng)前事務(wù)的執(zhí)行,那個(gè)該事務(wù)處在 失敗的 狀態(tài)。

  • 中止的(aborted)

如果事務(wù)執(zhí)行了一部分而變?yōu)?失敗的 狀態(tài),那么就需要把已經(jīng)修改的事務(wù)中的操作還原到事務(wù)執(zhí)行前的狀態(tài)(回滾)。這時(shí)該事務(wù)處在 中止的 狀態(tài)。

  • 提交的(committed)

當(dāng)一個(gè)處在 部分提交的 狀態(tài)的事務(wù)將修改過(guò)的數(shù)據(jù)都 同步到磁盤 上之后,我們就可以說(shuō)該事務(wù)處在了 提交的 狀態(tài)。

一個(gè)基本的狀態(tài)轉(zhuǎn)換圖如下所示:

MySQL 事務(wù)的基礎(chǔ)知識(shí)

如圖所示,只有當(dāng)事務(wù)處于 提交的 或者 中止的 狀態(tài)時(shí),一個(gè)事務(wù)的生命周期才算結(jié)束了。

  • 對(duì)于 已經(jīng)提交的事務(wù) 來(lái)說(shuō),該事務(wù)對(duì)數(shù)據(jù)庫(kù)所做的修改將 永久生效。
  • 對(duì)于 處于中止?fàn)顟B(tài)的事務(wù),該事務(wù)對(duì)數(shù)據(jù)庫(kù)所做的所有修改都 會(huì)被回滾到?jīng)]執(zhí)行該事務(wù)之前的狀態(tài)。

2.如何使用事務(wù)

一個(gè)事務(wù)的完整過(guò)程:

步驟1:開(kāi)啟事務(wù)

步驟2:一系列的 dml 操作 ...

步驟3:事務(wù)結(jié)束的狀態(tài)(提交 commit,中止 rollback)

使用事務(wù)有兩種方式,分別為 顯示事務(wù)隱式事務(wù)。

2.1 顯式事務(wù)

start transaction 或者 begin,作用是 顯式開(kāi)啟一個(gè)事務(wù)。

步驟1:開(kāi)啟事務(wù)

BEGIN;
# 或者
START TRANSACTION;

注意:使用以上的方式開(kāi)啟事務(wù),是不受 autocommit (自動(dòng)提交)變量影響的。

start transaction 語(yǔ)句相較于 begin?特別之處在于,后面能跟隨幾個(gè) 修飾符

  • read only:只讀事務(wù)。屬于該事務(wù)的數(shù)據(jù)庫(kù)操作 只能讀取數(shù)據(jù),不能修改數(shù)據(jù)。

補(bǔ)充:只讀事務(wù)中只是不允許修改哪些其他事務(wù)也能訪問(wèn)到表中的數(shù)據(jù)(事務(wù)共享表 - 數(shù)據(jù)),對(duì)于臨時(shí)表來(lái)說(shuō)(使用 create tmeporary table 創(chuàng)建的表),由于它們只能在當(dāng)前會(huì)話中可見(jiàn)(事務(wù)獨(dú)享表 - 數(shù)據(jù)),所以只讀事務(wù)其實(shí)也是可以對(duì)臨時(shí)表進(jìn)行增,刪,改操作的。

  • read write:可讀寫事務(wù)(默認(rèn))。屬于該事務(wù)的數(shù)據(jù)庫(kù)操作 可以讀取數(shù)據(jù),也可以修改數(shù)據(jù)
  • with consistent snapshot:開(kāi)啟一致性讀。

比如:

START TRANSACTION READ only;  # 開(kāi)啟一個(gè)只讀事務(wù)

START TRANSACTION READ only, WITH CONSISTENT SNAPSHOT; # 開(kāi)啟只讀事務(wù)和一致性讀

START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT; # 開(kāi)啟讀寫事務(wù)和一致性讀

步驟2:一系列事務(wù)中的操作(主要是dml操作,不含ddl)

步驟3:事務(wù)結(jié)束的狀態(tài)(提交 commit,中止 rollback)

# 提交事務(wù),當(dāng)提交事務(wù)后,對(duì)數(shù)據(jù)庫(kù)的修改時(shí)永久性的
commit; 
# 回滾事務(wù),即撤銷正在進(jìn)行的所有沒(méi)有提交的修改
rollback;
# 將事務(wù)回滾到某個(gè)保存點(diǎn)
rollback to [savepoint];

其中關(guān)于 savepoint 相關(guān)操作有:

  • 創(chuàng)建保存點(diǎn):
# 在事務(wù)中創(chuàng)建保存點(diǎn),方便后續(xù)針對(duì)保存點(diǎn)進(jìn)行回滾,一個(gè)事務(wù)中可以存在多個(gè)保存點(diǎn)
savepoint 保存點(diǎn)名稱;
  • 刪除保存點(diǎn):
# 刪除某個(gè)保存點(diǎn)
release savepoint 保存點(diǎn)名稱;

2.2 隱式事務(wù)

MySQL 中有一個(gè)系統(tǒng)變量 autocommit(默認(rèn):開(kāi)啟)

  • 查看 autocommit
SHOW VARIABLES LIKE 'autocommit';
# 或者
SELECT @@autocommit;
# 或者
SELECT @@global.autocommit;
  • 設(shè)置 autocommit
SET autocommit = TRUE; # 會(huì)話級(jí)別,只在當(dāng)前會(huì)話生效
# 或者
SET GLOBAL autocommit = TRUE; # 注意:全局設(shè)置,MySQL服務(wù)器重啟后失效

默認(rèn)情況下,如果我們不顯式的使用 start transaction 或者 begin 語(yǔ)句開(kāi)啟一個(gè)事務(wù),那么每一條語(yǔ)句都算是一個(gè)獨(dú)立的事務(wù),這種特性稱之為事務(wù)的 自動(dòng)提交。也就是說(shuō),不以 start transaction 或者 begin 語(yǔ)句顯式的開(kāi)啟一個(gè)事務(wù),那么執(zhí)行的 dml 操作就相當(dāng)于放到獨(dú)立的事務(wù)中執(zhí)行。

關(guān)閉 自動(dòng)提交 的功能兩中方法:

  • 顯式使用 start transaction 或者 begin 語(yǔ)句開(kāi)啟一個(gè)事務(wù)。這樣在本次事務(wù)提交或者回滾前會(huì)暫時(shí)關(guān)閉 自動(dòng)提交 的功能。
  • 把系統(tǒng)變量 autocommit 的值設(shè)置為 OFF。
SET autocommit = false; # 會(huì)話級(jí)別,只在當(dāng)前會(huì)話生效
#或者
SET autocommit = OFF; # 會(huì)話級(jí)別,只在當(dāng)前會(huì)話生效
#或者
SET autocommit = 0; # 會(huì)話級(jí)別,只在當(dāng)前會(huì)話生效

這樣的話,寫入的多條語(yǔ)句就算是屬于同一個(gè)事務(wù)了,直到我們顯式的寫出 commit 或者 rollback?(提交或回滾)

補(bǔ)充:Oracle 默認(rèn)不自動(dòng)提交事務(wù),需要手動(dòng) commit 或者 rollback,而 MySQL 默認(rèn)自動(dòng)提交。

2.3 隱式提交數(shù)據(jù)的情況(重要)

  • 使用數(shù)據(jù)庫(kù)定義語(yǔ)言(DDL)

當(dāng)我們使用 create,alter,drop 等語(yǔ)句去 修改數(shù)據(jù)庫(kù)對(duì)象 時(shí)(數(shù)據(jù)庫(kù),表,視圖,觸發(fā)器,存儲(chǔ)過(guò)程,視圖),就會(huì)隱式的提交前面語(yǔ)句所屬于的事務(wù):

begin; # 開(kāi)啟事務(wù)
select .... # 事務(wù)中的語(yǔ)句
update .... # 事務(wù)中的語(yǔ)句
.... # 事務(wù)中的語(yǔ)句

create table .... # 此時(shí)會(huì)隱式的提交前邊語(yǔ)句所屬于的事務(wù) 
  • 隱式使用或者修改 "mysql" 庫(kù)中的表(這里的mysql指的系統(tǒng)數(shù)據(jù)庫(kù)中名字為 "mysql" 數(shù)據(jù)庫(kù))。

當(dāng)我們使用 alter user,create user,drop user,grant,rename user,revoke,set password 等語(yǔ)句 修改用戶,權(quán)限 時(shí)也會(huì)隱式的提交前邊語(yǔ)句所屬于的事務(wù)。

  • 使用 "事務(wù)控制" 或關(guān)于 "鎖" 定的語(yǔ)句

    • 當(dāng)我們?cè)谝粋€(gè)事務(wù)中還沒(méi)提交或者回滾時(shí)就又使用 start transaction 或者 begin 語(yǔ)句開(kāi)啟了另一個(gè)事務(wù)時(shí),會(huì) 隱式的提交 上一個(gè)事務(wù):
    begin; # 開(kāi)啟事務(wù)
    select .... # 事務(wù)中的語(yǔ)句
    update .... # 事務(wù)中的語(yǔ)句
    .... # 事務(wù)中的語(yǔ)句
    
    begin; # 又開(kāi)啟了一個(gè)事務(wù) 此時(shí)會(huì)隱式的提交上一個(gè)事務(wù) 
    
    • 當(dāng)前的 autocommit 系統(tǒng)變量的值為 OFF,我們手動(dòng)修改為 ON 時(shí),也會(huì) 隱式的提交 前面語(yǔ)句所屬的事務(wù)。
    • 使用 lock tables,unlock tables 等關(guān)于 "鎖" 定的語(yǔ)句時(shí)也會(huì) 隱式的提交 前邊語(yǔ)句所屬的事務(wù)。
  • 關(guān)于 MySQL 復(fù)制的一些語(yǔ)句(主從復(fù)制)

使用 start slave,stop slave,reset slave,change master to 等語(yǔ)句時(shí)會(huì) 隱式的提交 前邊語(yǔ)句所屬的事務(wù)。

  • 其他的一些語(yǔ)句

使用 analyze table(分析表),cache index,check table(檢查表),flush(刷新),load index into cache,optimize table(優(yōu)化表),repair table,reset 等語(yǔ)句也會(huì) 隱式的提交 前邊語(yǔ)句所屬的事務(wù)。

2.4 舉例:提交與回滾 - 顯式與隱式

# 創(chuàng)建測(cè)試表
create TABLE IF NOT EXISTS xld_begin(
id INT UNSIGNED PRIMARY KEY auto_increment COMMENT '主鍵id',
name VARCHAR(15) NOT NULL COMMENT '名稱',
age TINYINT UNSIGNED COMMENT '年齡',
INDEX idx_age(age)
)ENGINE = INNODB DEFAULT CHARSET = utf8;
  • 回滾(rollback) - 事務(wù)
# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 查看自動(dòng)提交是否開(kāi)啟
SHOW VARIABLES LIKE '%autocommit%'; # ON 開(kāi)啟

# 給表添加一條記錄
INSERT INTO xld_begin(name,age)VALUE ('張三',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 開(kāi)啟一個(gè)事務(wù)
BEGIN;

# 在事務(wù)中添加一條記錄
INSERT INTO xld_begin(name,age) VALUE ('李四',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 程序錯(cuò)誤
INSERT INTO xld_begin(name,age)VALUE (NULL,10);

# 回滾事務(wù) - 事務(wù)結(jié)束
ROLLBACK;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;
  • 提交(commit) - 事務(wù)
# 清空表 (DDL)不受事務(wù)控制
TRUNCATE TABLE xld_begin;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 查看自動(dòng)提交是否開(kāi)啟
SHOW VARIABLES LIKE '%autocommit%'; # ON 開(kāi)啟

# 給表添加一條記錄
INSERT INTO xld_begin(name,age)VALUE ('張三',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 開(kāi)啟一個(gè)事務(wù)
BEGIN;

# 在事務(wù)中給表添加一條記錄
insert into xld_begin(name,age) VALUE ('李四',12);

# 修改張三的年齡
update xld_begin set age = 12 WHERE name = '張三';

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 提交事務(wù) - 事務(wù)結(jié)束
COMMIT;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;
  • 鏈?zhǔn)聞?wù)
# 清空表 (DDL)不受事務(wù)控制
TRUNCATE TABLE xld_begin;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 查看自動(dòng)提交是否開(kāi)啟
SHOW VARIABLES LIKE '%autocommit%'; # ON 開(kāi)啟

# 開(kāi)啟鏈?zhǔn)聞?wù)
SET @@SESSION.completion_type = 1;

# 查看鏈?zhǔn)聞?wù)是否開(kāi)啟成功
SELECT @@session.completion_type;

# 給表添加一條記錄
INSERT INTO xld_begin(name,age)VALUE ('張三',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 開(kāi)啟事務(wù)
BEGIN;

# 在事務(wù)中給表添加一條記錄
insert into xld_begin(name,age) VALUE ('李四',12);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 提交事務(wù) - 事務(wù)結(jié)束
COMMIT;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

# 在事務(wù)中給表添加一條記錄
insert into xld_begin(name,age) VALUE ('王五',14);

# 程序錯(cuò)誤
INSERT INTO xld_begin(name,age)VALUE (NULL,10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

ROLLBACK;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin;

completion_type 系統(tǒng)變量(全局/會(huì)話)的使用:

  • 查看 completion_type
SHOW VARIABLES LIKE '%completion%';
# 或者
SELECT @@completion_type;
  • 設(shè)置 completion_type
SET @@completion_type = 1; # 開(kāi)啟鏈?zhǔn)绞聞?wù)
  • completion_type 的參數(shù)配置說(shuō)明:
    • completion_type = 0(默認(rèn)),當(dāng)我們執(zhí)行 commit 時(shí)會(huì)提交事務(wù),在執(zhí)行下一個(gè)事務(wù)時(shí),需要使用 start transaction 或者 begin 來(lái)開(kāi)啟。
    • completion_type = 1,這種情況下,當(dāng)我們執(zhí)行 commit 提交事務(wù)后,相當(dāng)于執(zhí)行了 commit and chain,也就是開(kāi)啟一個(gè) 鏈?zhǔn)绞聞?wù),即當(dāng)我們提交事務(wù)之后會(huì)開(kāi)啟一個(gè)相同隔離級(jí)別的事務(wù)。(注意:此時(shí)的"自動(dòng)提交"是失效的,必須手動(dòng)結(jié)束事務(wù)
    • completion_type = 2,這種情況下 commit = commit and release,當(dāng)我們執(zhí)行 commit 提交事務(wù)后,會(huì)自動(dòng)與服務(wù)器斷開(kāi)連接

2.5 測(cè)試 innodb 與 myisam 事務(wù)的支持情況

# 創(chuàng)建 innodb 事務(wù)表
create TABLE IF NOT EXISTS xld_begin_innodb(
id int UNSIGNED PRIMARY KEY auto_increment COMMENT '主鍵id',
name VARCHAR(15) NOT NULL COMMENT '名稱',
age TINYINT UNSIGNED COMMENT '年齡',
INDEX idx_age(age)
) ENGINE = INNODB DEFAULT charset = utf8;

# 創(chuàng)建 myisam 事務(wù)表
create TABLE IF not EXISTS xld_begin_myisam(
id INT UNSIGNED PRIMARY KEY auto_increment COMMENT '主鍵id',
name VARCHAR(15) NOT NULL COMMENT '名稱',
age TINYINT UNSIGNED COMMENT '年齡',
index idx_age(age)
)ENGINE = myisam DEFAULT charset = utf8;
  • Innodb 存儲(chǔ)引擎支持事務(wù)
# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_innodb;

# 開(kāi)啟事務(wù)
BEGIN;

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_innodb(name,age) value ('張三',10);

# 程序錯(cuò)誤
INSERT INTO xld_begin_innodb(name,age) value (NULL,10);

# 回滾事務(wù) - 事務(wù)結(jié)束
ROLLBACK;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_innodb;
  • Myisam 存儲(chǔ)引擎不支持事務(wù)
# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_myisam;

# 開(kāi)啟事務(wù)
BEGIN;

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_myisam(name,age) value ('張三',12);

# 程序錯(cuò)誤
INSERT INTO xld_begin_myisam(name,age) value (NULL,12);

# 回滾事務(wù) - 事務(wù)結(jié)束
ROLLBACK;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_myisam;

2.6 舉例 :事務(wù)保存點(diǎn)(savepoint)

# 創(chuàng)建表
create TABLE IF not EXISTS xld_begin_savepoint(
id int UNSIGNED PRIMARY KEY auto_increment COMMENT '主鍵id',
name VARCHAR(15) not null COMMENT '名稱',
age TINYINT UNSIGNED COMMENT '年齡',
index idx_age(age)
)ENGINE = INNODB DEFAULT charset = utf8;
  • 保存點(diǎn)的使用
# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

# 開(kāi)啟事務(wù)
BEGIN;

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_savepoint(name,age) value ('張三',10);

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_savepoint(name,age) value ('李四',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

# 創(chuàng)建保存點(diǎn)
savepoint xld_savepoint1;

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_savepoint(name,age) value ('王五',10);

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_savepoint(name,age) value ('劉六',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

# 創(chuàng)建保存點(diǎn)
savepoint xld_savepoint2;

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_savepoint(name,age) value ('王八',10);

# 在事務(wù)中給表添加一條記錄
INSERT INTO xld_begin_savepoint(name,age) value ('林九',10);

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

# 回滾到保存點(diǎn) xld_savepoint2
ROLLBACK TO xld_savepoint2; # 注意:此時(shí),事務(wù)還未結(jié)束

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

# 回滾到保存點(diǎn) xld_savepoint1
ROLLBACK TO xld_savepoint1; # 注意:此時(shí),事務(wù)還未結(jié)束

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

# 提交事務(wù) - 事務(wù)結(jié)束
COMMIT;

# 查詢數(shù)據(jù)
SELECT * FROM xld_begin_savepoint;

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

MySQL 是一個(gè) 客戶端(C)/ 服務(wù)器(S) 架構(gòu)的軟件,對(duì)于同一個(gè)服務(wù)器來(lái)說(shuō),可以有若干個(gè)客戶端與之連接,每個(gè)客戶端與服務(wù)器連接上之后,就可以稱為一個(gè)會(huì)話(Session)。

每個(gè)客戶端可以在自己的會(huì)話中向服務(wù)器發(fā)出請(qǐng)求語(yǔ)句(DML),一個(gè)請(qǐng)求語(yǔ)句(DML)可能是某個(gè)事務(wù)的一部分,也就是說(shuō) MySQL 服務(wù)器可能會(huì)同時(shí)處理多個(gè)事務(wù)。事務(wù)是有 隔離 的特性的,理論上在某個(gè)事務(wù) 對(duì)某個(gè)數(shù)據(jù)進(jìn)行訪問(wèn) 時(shí),其他事務(wù)應(yīng)該進(jìn)行 排隊(duì),當(dāng)該事務(wù)提交之后,其他事務(wù)才可以繼續(xù)訪問(wèn)這個(gè)數(shù)據(jù)。但是這樣對(duì) 性能影響太大,我們既想保持事務(wù)的 隔離性,又想讓服務(wù)器在處理多個(gè)事務(wù)時(shí)(同一個(gè)數(shù)據(jù)) 性能盡量高些,那就看二者如何權(quán)衡取舍了。

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

# 自己想辦法吧?。?!

3.2 數(shù)據(jù)并發(fā)問(wèn)題

針對(duì)事務(wù)的隔離性和并發(fā)性,我們?cè)趺醋鋈∩崮??先看一下訪問(wèn)相同數(shù)據(jù)的事務(wù)在 不保證串行執(zhí)行(也就是執(zhí)行完一個(gè)再執(zhí)行另一個(gè))的情況下可能會(huì)出現(xiàn)哪些問(wèn)題:

1. 臟寫(Dirty Write)

有兩個(gè)事務(wù):事務(wù)A,事務(wù)B。如果 事務(wù)A 修改了 另一個(gè) 事務(wù)B 修改過(guò)且未提交 的數(shù)據(jù),那就意味著發(fā)生了 臟寫,示意圖如下:

MySQL 事務(wù)的基礎(chǔ)知識(shí)

有兩個(gè)事務(wù):事務(wù)A,事務(wù)B ,事務(wù)B 先將 id 為1的name更新為 '李四',然后 事務(wù)A 接著又把這條 id 為1的name更新為 ’張三‘ 且提交(commit)了。如果之后 事務(wù)B 進(jìn)行了回滾,那么 事務(wù)A 中的更新也將不復(fù)存在,這種現(xiàn)象就稱之為 臟寫。這時(shí) 事務(wù)A 就沒(méi)有效果了,明明把數(shù)據(jù)更新了,最后也提交事務(wù)了,最后看到的數(shù)據(jù)什么變化也沒(méi)有。

在 MySQL 默認(rèn)的事務(wù)隔離級(jí)別下,在 事務(wù)A 中執(zhí)行的更新語(yǔ)句會(huì)處于等待狀態(tài)(加鎖了)。

2. 臟讀(Dirty Read)

有兩個(gè)事務(wù):事務(wù)A,事務(wù)B。事務(wù)A 讀取 了已經(jīng)被 事務(wù)B 更新但還沒(méi)有提交 的數(shù)據(jù)。之后若 事務(wù) B 回滾,事務(wù)A 讀取 的內(nèi)容就是 臨時(shí)且無(wú)效 的。(一個(gè)事務(wù)讀到了,另一個(gè)事務(wù)修改了但未提交的數(shù)據(jù)

MySQL 事務(wù)的基礎(chǔ)知識(shí)

有兩個(gè)事務(wù):事務(wù)A,事務(wù)B ,事務(wù)B 先將 id 為1的name更新為 '張三',然后 事務(wù)A 再去查詢這條 id 為1的記錄,如果讀的name的值為'張三',而 事務(wù)B 不久之后進(jìn)行了回滾,那么 事務(wù)A 中就相當(dāng)于讀到了一個(gè)不存在的數(shù)據(jù),這種現(xiàn)象就稱之為 臟讀

3. 不可重復(fù)讀(Non-Repeatable Read)

有兩個(gè)事務(wù):事務(wù)A,事務(wù)B。事務(wù)A 讀取 了一條記錄,然后在 事務(wù)B 中 更新了且提交(commit)該記錄。隨之 事務(wù)A 再次讀取了該記錄,值就不同了。那這就意味著發(fā)生了 不可重復(fù)讀。(在同一個(gè)事務(wù)中,多次執(zhí)行相同的語(yǔ)句,但每次讀取的結(jié)果不同

MySQL 事務(wù)的基礎(chǔ)知識(shí)

有兩個(gè)會(huì)話 sessionA,sessionB。session B 中提交了幾個(gè) 隱式事務(wù)(注意是隱式事務(wù),意味著語(yǔ)句結(jié)束事務(wù)就提交了),這些事務(wù)都修改了 id 為1的name值,每次事務(wù)提交之后,如果 Session A 中的事務(wù)都可以查看到最新的值,這種現(xiàn)象也被稱之為 不可重復(fù)讀。

4. 幻讀(Phantom)

有兩個(gè)事務(wù):事務(wù)A,事務(wù)B。事務(wù)A 從一個(gè)表中 讀取 了一條記錄,然后 事務(wù)B 給該表 插入 了一些新的記錄。之后,如果 事務(wù)A 再次讀取 同一個(gè)表,結(jié)果集出現(xiàn)了多幾行的話。那就意味著發(fā)生了 幻讀。()

MySQL 事務(wù)的基礎(chǔ)知識(shí)

有兩個(gè)會(huì)話 sessionA,sessionB。session A 中的事務(wù)先根據(jù)條件 id > 0 這個(gè)條件查詢數(shù)據(jù),得到了 name 為 '張三' 的記錄。之后 session B 中提交了一個(gè) 隱式事務(wù),該事務(wù)向表中插入了一條新紀(jì)錄。之后 session A 中的事務(wù)再次根據(jù)相同的條件 id > 0 查詢數(shù)據(jù),得到的結(jié)果集中包含了 session B 中的事務(wù)新插入的那條記錄,這種現(xiàn)象也就稱為 幻讀(我們把新插入的那些記錄稱之為 幻影記錄)。

注意1:

有的人會(huì)有疑問(wèn),那如果 session B 中 刪除了 一些符合 id > 0 的記錄而不是插入新紀(jì)錄,那 session A 之后再根據(jù) id > 0 的條件讀取的 記錄變少了,這種現(xiàn)象算不算 幻讀 呢?這種現(xiàn)象 不屬于幻讀幻讀 強(qiáng)調(diào)的是一個(gè)事務(wù)按照某個(gè) 相同條件多次讀取 記錄時(shí),后讀取時(shí)讀到了之前 沒(méi)有讀到的記錄。

注意2:

那對(duì)于先前已經(jīng)讀到的記錄,之后又讀取不到這種情況,算啥呢?這相當(dāng)于對(duì)每一條記錄都發(fā)生了 不可重復(fù)讀 的現(xiàn)象。幻讀 只是 重點(diǎn)強(qiáng)調(diào)了現(xiàn)在讀取到了,之前讀取時(shí) ,沒(méi)有獲取的到記錄。

3.3 SQL 中的四種隔離級(jí)別

上面介紹了幾種并發(fā)事務(wù)執(zhí)行過(guò)程中可能遇到的一些問(wèn)題,這些問(wèn)題有輕重緩急之分,我們給這些問(wèn)題按照嚴(yán)重性排一下序:

臟寫 > 臟讀 > 不可重復(fù)讀 > 幻讀

如何通過(guò)舍棄一部分隔離性來(lái)?yè)Q取一部分性能呢?

答:設(shè)立一些隔離級(jí)別,隔離級(jí)別越低,并發(fā)問(wèn)題發(fā)生的就越多,性能就越好

SQL 標(biāo)準(zhǔn) 中設(shè)立了4個(gè) 隔離級(jí)別

  • read uncommitted(讀未提交): 在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。不能避免:臟讀,不可重復(fù)讀,幻讀。
  • read committed(讀已提交):該隔離級(jí)別滿足了隔離的簡(jiǎn)單定義:一個(gè)事務(wù)只能看見(jiàn)已經(jīng)提交事務(wù)所做的改變。這也是大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)的默認(rèn)隔離級(jí)別(但不是 MySQL 默認(rèn) 的)。可以避免臟讀。但不能避免:不可重復(fù)讀,幻讀
  • repeatable read(可重復(fù)讀):該隔離級(jí)別可以做到,事務(wù)A 在讀到一條數(shù)據(jù)之后,此時(shí) 事務(wù)B 對(duì)該數(shù)據(jù)進(jìn)行了修改并提交,那么 事務(wù)A 再讀該數(shù)據(jù),讀到的還是原來(lái)的內(nèi)容。可以避免臟讀,不可重復(fù)讀。但不能避免:幻讀
  • serializable(可串行化):該隔離級(jí)別可以確保事務(wù)在多次讀取表中數(shù)據(jù)時(shí)都是相同的數(shù)據(jù)。在這事務(wù)持續(xù)期間,禁止其他事務(wù)對(duì)該表執(zhí)行插入,更新和刪除操作。所有的并發(fā)問(wèn)題都可以避免,但性能十分低下。

SQL 標(biāo)準(zhǔn) 中規(guī)定,針對(duì)不同的隔離級(jí)別,并發(fā)事務(wù)可以發(fā)生不同的問(wèn)題,具體情況如下:

MySQL 事務(wù)的基礎(chǔ)知識(shí)

注意:由于"臟寫"這個(gè)問(wèn)題太嚴(yán)重了,不論是那種隔離級(jí)別,都不允許"臟寫"的情況發(fā)生。

不同的隔離級(jí)別有不同的現(xiàn)象,并有不同的鎖和并發(fā)機(jī)制,隔離級(jí)別越高,數(shù)據(jù)庫(kù)的并發(fā)性能就越差,4種事務(wù)隔離級(jí)別與并發(fā)性能的關(guān)系如下:

MySQL 事務(wù)的基礎(chǔ)知識(shí)

3.4 MySQL 支持的四種隔離級(jí)別

不同的數(shù)據(jù)庫(kù)廠商對(duì) SQL 標(biāo)準(zhǔn)中規(guī)定的四種隔離級(jí)別的支持也是不一樣的。比如,Oracle 就只支持 read committed(讀已提交,默認(rèn)隔離級(jí)別)serializable(串行化)。MySQL 雖然支持4種隔離級(jí)別,但與 SQL 標(biāo)準(zhǔn)中所規(guī)定的各級(jí)隔離級(jí)別允許發(fā)生的問(wèn)題卻有些出入,MySQL 在 repeatable read(可重復(fù)讀) 隔離級(jí)別下,是可以禁止 幻讀 問(wèn)題發(fā)生的。

MySQL 的默認(rèn)隔離級(jí)別為:repeatable read

  • 查看 MySQL 的默認(rèn)隔離級(jí)別:transaction_isolation全局/會(huì)話
# 5.7.20 版本之前使用:
SHOW VARIABLES LIKE '%tx_isolation%';

# 5.7.20 版本之后使用(transaction_isolation 替換了 tx_isolation):
SHOW VARIABLES LIKE '%transaction_isolation%';

# 或者
SELECT @@transaction_isolation; # 同時(shí)支持全局和會(huì)話

3.5 如何設(shè)置事務(wù)的隔離級(jí)別

通過(guò)下面的語(yǔ)句修改事務(wù)的隔離級(jí)別:

  • 方式1:
set [global | session] transaction isolation level 隔離級(jí)別;
# 其中,隔離級(jí)別格式:
> read uncommitted
> read committed
> repeatable read
> serializable

例如:設(shè)置會(huì)話中的隔離級(jí)別為:讀已提交

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • 方式2:
set [global | session] transaction_isolation = '隔離級(jí)別';
# 其中,隔離級(jí)別格式:
> read-uncommitted
> read-committed
> repeatable-read
> serializable

例如:設(shè)置會(huì)話中的隔離級(jí)別為:讀已提交

SET SESSION TRANSACTION_ISOLATION = 'read-committed';

關(guān)于設(shè)置時(shí)使用 globalsession 的影響:

  • 使用 global 關(guān)鍵字(在全局范圍影響):
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
#或者
SET GLOBAL TRANSACTION_ISOLATION = 'read-committed';

注意:

  • 當(dāng)前已經(jīng)存在的會(huì)話無(wú)效
  • 只對(duì)執(zhí)行完該語(yǔ)句之后產(chǎn)生的會(huì)話起作用
  • 使用 session 關(guān)鍵字(在會(huì)話范圍影響):
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
#或者
SET SESSION TRANSACTION_ISOLATION = 'read-committed';

注意:

  • 對(duì)當(dāng)前會(huì)話的所有后續(xù)的事務(wù)有效
  • 如果在事務(wù)與事務(wù)之間執(zhí)行,則對(duì)后續(xù)的事務(wù)有效
  • 該語(yǔ)句可以在已經(jīng)開(kāi)啟事務(wù)中間執(zhí)行,但不會(huì)影響當(dāng)前正在執(zhí)行的事務(wù),只對(duì)后續(xù)的事務(wù)有效

如果在服務(wù)器啟動(dòng)時(shí)相改變事務(wù)的默認(rèn)隔離級(jí)別,可以修改啟動(dòng)參數(shù) transaction_isolation 的值。比如,在啟動(dòng)服務(wù)器指定了 transaction_isolation = read-committed。那么事務(wù)的默認(rèn)隔離級(jí)別就從原來(lái)的 repeatable-read(可重復(fù)讀) 變成了 read-committed(讀已提交)

小結(jié):

數(shù)據(jù)庫(kù)規(guī)定了多種事務(wù)的隔離級(jí)別,不同隔離級(jí)別對(duì)應(yīng)不同的干擾程度,隔離級(jí)別越高,數(shù)據(jù)一致性就越好,但相對(duì)的并發(fā)性能就越差。

3.6 不同隔離級(jí)別舉例

  • 初始化數(shù)據(jù):
# 創(chuàng)建表
create table if not exists xld_transaction_isolation(
id INT PRIMARY KEY auto_increment COMMENT '主鍵id',
name VARCHAR(15) not NULL COMMENT '名稱',
money int DEFAULT 0 COMMENT '金額'
)ENGINE = INNODB DEFAULT charset = utf8;

# 新增數(shù)據(jù)
INSERT into xld_transaction_isolation (name,money) VALUES('張三',100),('李四',80);

# 查詢數(shù)據(jù)
SELECT * FROM xld_transaction_isolation;
# 初始化表中數(shù)據(jù):
id	name monry	
1	張三	100
2	李四	80

1. 演示:臟讀 - 讀未提交(read-uncommitted):

  1. 事務(wù)A 先執(zhí)行:
# 設(shè)置事務(wù)隔離級(jí)別為:讀未提交
SET SESSION transaction_isolation = 'read-uncommitted';

# 查看事務(wù)的隔離級(jí)別
SELECT @@transaction_isolation;

# 開(kāi)啟事務(wù)
BEGIN;

# 修改張三的余額
UPDATE xld_transaction_isolation SET money =  money + 50 WHERE NAME = '張三';

# 查詢數(shù)據(jù)
SELECT * FROM xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	150
2	李四	80
  1. 事務(wù)B 再執(zhí)行:
# 設(shè)置事務(wù)隔離級(jí)別為:讀未提交
SET SESSION transaction_isolation = 'read-uncommitted';

# 查看事務(wù)的隔離級(jí)別
SELECT @@transaction_isolation;

# 開(kāi)啟事務(wù)
BEGIN;

# 查詢數(shù)據(jù)
SELECT * FROM xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	150
2	李四	80

**此時(shí)可以看到在 事務(wù)B 中讀取了到 事務(wù)A修改了但未提交 的數(shù)據(jù)。這時(shí)就出現(xiàn)了 臟讀 問(wèn)題。 **

2. 演示:避免臟讀 - (read-committed

  1. 事務(wù)A 先執(zhí)行:
# 設(shè)置事務(wù)隔離級(jí)別為:讀已提交
SET SESSION transaction_isolation = 'read-committed';

# 查看事務(wù)的隔離級(jí)別
SELECT @@transaction_isolation;

# 開(kāi)啟事務(wù)
BEGIN;

# 修改張三的余額
UPDATE xld_transaction_isolation SET money =  money + 50 WHERE NAME = '張三';

# 查詢數(shù)據(jù)
SELECT * FROM xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	150
2	李四	80
  1. 事務(wù)B 再執(zhí)行:
# 設(shè)置事務(wù)隔離級(jí)別為:讀已提交
SET SESSION transaction_isolation = 'read-committed';

# 查看事務(wù)的隔離級(jí)別
SELECT @@transaction_isolation;

# 開(kāi)啟事務(wù)
BEGIN;

# 查詢數(shù)據(jù)
SELECT * FROM xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	100
2	李四	80

**此時(shí)可以看到在 事務(wù)B 中并沒(méi)有讀取到 事務(wù)A修改了但未提交 的數(shù)據(jù)。避免了 臟讀 問(wèn)題。 **

  1. 之后 事務(wù)A 提交修改的數(shù)據(jù):
.......
# 提交
COMMIT;
  1. 隨之在 事務(wù)B 中再次執(zhí)行查詢:
.......
# 查詢數(shù)據(jù)
SELECT * FROM xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	150
2	李四	80

此時(shí)可以看到 事務(wù)B 中讀取到了 事務(wù)A修改了并提交 的數(shù)據(jù)。

這時(shí)我們可能明顯的看到在 事務(wù)B 中 ,兩次查詢的值是不同的,這時(shí)就出現(xiàn)了 不可重復(fù)讀 問(wèn)題。

3. 演示:避免不可重復(fù)讀 - (repeatable-read

  1. 事務(wù)A 先執(zhí)行
# 設(shè)置事務(wù)的隔離級(jí)別為:可重復(fù)讀
SET SESSION TRANSACTION_ISOLATION = 'repeatable-read';

# 查看事務(wù)的隔離級(jí)別
SELECT @@transaction_isolation;

#開(kāi)啟事務(wù)
BEGIN;

# 查詢數(shù)據(jù) - 事務(wù)B 未提交修改的數(shù)據(jù)之前
SELECT * from xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	100
2	李四	80
  1. 事務(wù)B 再執(zhí)行
# 設(shè)置事務(wù)的隔離級(jí)別為:可重復(fù)讀
SET SESSION TRANSACTION_ISOLATION = 'repeatable-read';

# 查看事務(wù)的隔離級(jí)別
SELECT @@transaction_isolation;
	
# 開(kāi)啟事務(wù)
BEGIN;

# 修改張三余額
UPDATE xld_transaction_isolation SET money = money - 50 where name = '張三';

# 查詢數(shù)據(jù)
SELECT * from xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	50
2	李四	80
# 提交事務(wù)
COMMIT;

# 查詢數(shù)據(jù)
SELECT * from xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	50
2	李四	80
  1. 之后 事務(wù)A 再次查詢數(shù)據(jù)
.......
# 查詢數(shù)據(jù) - 事務(wù)B 提交了修改的數(shù)據(jù)后
SELECT * from xld_transaction_isolation;
# 查詢的結(jié)果為:
id	name monry	
1	張三	100
2	李四	80

# 提交事務(wù)
COMMIT;

此時(shí)可以看到在 事務(wù)A 中并沒(méi)有讀取到了 事務(wù)B修改了并提交 的數(shù)據(jù),避免了 不可重復(fù)讀 的問(wèn)題。這時(shí)在 事務(wù)A 中讀取的數(shù)據(jù)是不受 其他事務(wù) 影響的。

4. 演示 - 幻讀

# 自己想辦法吧!

... 通過(guò)鎖(獨(dú)占鎖)來(lái)解決 幻讀 的問(wèn)題。后續(xù)章節(jié)會(huì)講到!

4. 事務(wù)的常見(jiàn)分類

從事務(wù)理論的角度來(lái)看,可以把事務(wù)分為以下幾種類型:

  • 扁平事務(wù)
  • 帶有保存點(diǎn)的扁平事務(wù)
  • 鏈?zhǔn)聞?wù)
  • 嵌套事務(wù)
  • 分布式事務(wù)

下面分別介紹這幾種類型:

  • 扁平事務(wù)

扁平事務(wù) 是事務(wù)類型中最簡(jiǎn)單的一種,也是使用最頻繁的事務(wù),在扁平事務(wù)中,所有操作都處于同一層次,由 start transaction 或者 begin 來(lái)開(kāi)啟,commit 或者 rollback 結(jié)束,其間的操作是原子的,要么都執(zhí)行,要么都回滾。因此,扁平事務(wù)是應(yīng)用程序成為原子操作的基本組成模塊。

扁平事務(wù)的三種結(jié)果

  1. 事務(wù)成功完成。
  2. 應(yīng)用程序要求停止事務(wù)。比如應(yīng)用程序在捕獲到異常時(shí)會(huì)回滾事務(wù)。
  3. 外界因素強(qiáng)制終止事務(wù)。比如連接超時(shí)或連接斷開(kāi)。
  • 帶有保存點(diǎn)的扁平事務(wù)

帶有保存點(diǎn)的扁平事務(wù) 除了支持扁平事務(wù)支持的操作外,還允許在事務(wù)執(zhí)行過(guò)程中回滾到同一事務(wù)中較早的一個(gè)狀態(tài),這是因?yàn)槟承┦聞?wù)可能在執(zhí)行過(guò)程中出現(xiàn)了錯(cuò)誤并不會(huì)導(dǎo)致所有的操作都無(wú)效,放棄整個(gè)事務(wù)不合乎要求,開(kāi)銷太大。

保存點(diǎn)(savepoint)用來(lái)通知事務(wù)系統(tǒng)應(yīng)該記住事務(wù)當(dāng)前的狀態(tài),以方便發(fā)送錯(cuò)誤時(shí),事務(wù)能回到保存點(diǎn)當(dāng)時(shí)的狀態(tài)。對(duì)于扁平的事務(wù)來(lái)說(shuō),隱式的設(shè)置了一個(gè)保存點(diǎn),然而在整個(gè)事務(wù)中,只有這一個(gè)保存點(diǎn),因此,回滾只能回滾到事務(wù)開(kāi)始的狀態(tài)。

  • 鏈?zhǔn)聞?wù)

鏈?zhǔn)聞?wù) 是指一個(gè)事務(wù)由多個(gè)子事務(wù)鏈?zhǔn)浇M成,它可以被視為保存點(diǎn)模式的一個(gè)變種。

帶有保存點(diǎn)的扁平事務(wù),當(dāng)發(fā)生系統(tǒng)崩潰時(shí),所有的保存點(diǎn)都將消失,這意味著當(dāng)進(jìn)行恢復(fù)時(shí),事務(wù)需要從開(kāi)始處重新執(zhí)行,而不能從最近的一個(gè)保存點(diǎn)繼續(xù)執(zhí)行。

鏈?zhǔn)聞?wù)的思想是:在提交一個(gè)事務(wù)時(shí),釋放不需要的數(shù)據(jù)對(duì)象,將必要的處理上下文隱式地傳給下一個(gè)要開(kāi)始的事務(wù),前一個(gè)子事務(wù)的提交操作和下一個(gè)子事務(wù)的開(kāi)始操作合并成一個(gè)原子操作,這意味著下一個(gè)事務(wù)將看到上一個(gè)事務(wù)的結(jié)果,就好像在一個(gè)事務(wù)中進(jìn)行一樣。這樣,在提交子事務(wù)就可以釋放不需要的數(shù)據(jù)對(duì)象,而不必等到整個(gè)事務(wù)完成后才釋放

MySQL 事務(wù)的基礎(chǔ)知識(shí)

鏈?zhǔn)聞?wù)與帶有保存點(diǎn)的扁平事務(wù)的不同之處在于:

  • 帶有保存點(diǎn)的扁平事務(wù)能回滾到任意正確的保存點(diǎn),而鏈?zhǔn)聞?wù)中的回滾僅限于當(dāng)前事務(wù),即只能恢復(fù)到最近的一個(gè)保存點(diǎn)。
  • 對(duì)于鎖的處理,兩者也不相同,鏈?zhǔn)聞?wù)在執(zhí)行 commit 后即釋放了當(dāng)前所持有的鎖,而帶有保存點(diǎn)的扁平事務(wù)不影響迄今為止所持有的鎖。
  • 嵌套事務(wù)

嵌套事務(wù) 是一個(gè)層次結(jié)構(gòu)框架,由一個(gè)頂層事務(wù)控制著各個(gè)層次的事務(wù),頂層事務(wù)之下嵌套的事務(wù)稱為子事務(wù),其控制著每一個(gè)局部的變換,子事務(wù)本身也可以是嵌套事務(wù)。因此,嵌套事務(wù)的層次結(jié)構(gòu)可以看成是一棵樹

  • 分布式事務(wù)

分布式事務(wù) 通常是在一個(gè)分布式環(huán)境下運(yùn)行的扁平事務(wù),因此,需要根據(jù)數(shù)據(jù)所在位置訪問(wèn)網(wǎng)絡(luò)中不同節(jié)點(diǎn)的數(shù)據(jù)庫(kù)資源。

例如:

一個(gè)銀行用戶從招商銀行的賬戶向工商銀行的賬戶轉(zhuǎn)賬 1000 元,這里需要用到分布式事務(wù),因?yàn)椴荒軆H調(diào)用某一家銀行的數(shù)據(jù)庫(kù)就完成任何。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-760681.html

到了這里,關(guān)于MySQL 事務(wù)的基礎(chǔ)知識(shí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【數(shù)據(jù)庫(kù)】MySQL概念性基礎(chǔ)知識(shí)期末復(fù)習(xí)

    第一章 3 二維表結(jié)構(gòu)……數(shù)據(jù)模型—— 關(guān)系數(shù)據(jù)模型 5 描述全部數(shù)據(jù)整體邏輯結(jié)構(gòu)—— 模式 6 邏輯數(shù)據(jù)獨(dú)立性—— 模式變,外模式和應(yīng)用程序不變 7 物理數(shù)據(jù)獨(dú)立性—— 內(nèi)模式變,外模式和應(yīng)用程序不變 9 R-(R-S)—— R∩S 10 從兩個(gè)關(guān)系笛卡爾積中選取他們屬性間滿足一定條

    2024年02月02日
    瀏覽(25)
  • MySQL入門指南:數(shù)據(jù)庫(kù)操作的基礎(chǔ)知識(shí)

    MySQL入門指南:數(shù)據(jù)庫(kù)操作的基礎(chǔ)知識(shí)

    當(dāng)談到關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS)時(shí),MySQL無(wú)疑是最常見(jiàn)和廣泛使用的一個(gè)。它是一個(gè)強(qiáng)大的工具,用于存儲(chǔ)、管理和檢索數(shù)據(jù)。在這篇博客中,我們將介紹MySQL的基本知識(shí),包括數(shù)據(jù)庫(kù)的操作、數(shù)據(jù)表的操作以及數(shù)據(jù)的增刪改查~~ 目錄 1. 數(shù)據(jù)庫(kù)的操作 1.1 創(chuàng)建數(shù)據(jù)庫(kù) 1.2 刪除

    2024年02月07日
    瀏覽(39)
  • 【MySQL數(shù)據(jù)庫(kù)重點(diǎn)】第二節(jié):MySQL基礎(chǔ)知識(shí)(基本操作)

    目錄 一:數(shù)據(jù)庫(kù)的操作 1.顯示數(shù)據(jù)庫(kù) 2.創(chuàng)建數(shù)據(jù)庫(kù) 3.使用數(shù)據(jù)庫(kù) 4.刪除數(shù)據(jù)庫(kù) 二:常用數(shù)據(jù)類型 1.數(shù)值類型:整型和浮點(diǎn)型 2.字符串類型 3.日期類型 三:表的操作 1.查看表結(jié)構(gòu) 2.創(chuàng)建表 3.刪除表 1.顯示數(shù)據(jù)庫(kù) 語(yǔ)法: show databases;? 2.創(chuàng)建數(shù)據(jù)庫(kù) (1)簡(jiǎn)化語(yǔ)法 create database?數(shù)

    2024年02月08日
    瀏覽(24)
  • MySQL 基礎(chǔ)知識(shí)(一)之?dāng)?shù)據(jù)庫(kù)和 SQL 概述

    MySQL 基礎(chǔ)知識(shí)(一)之?dāng)?shù)據(jù)庫(kù)和 SQL 概述

    目錄 1 數(shù)據(jù)庫(kù)相關(guān)概念 2 數(shù)據(jù)庫(kù)的結(jié)構(gòu) ?3 SQL 概要 4 SQL 的基本書寫規(guī)則 1 數(shù)據(jù)庫(kù)相關(guān)概念 數(shù)據(jù)庫(kù)是將大量的數(shù)據(jù)保存起來(lái),通過(guò)計(jì)算機(jī)加工而成的可以進(jìn)行高效訪問(wèn)的數(shù)據(jù)集合 數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)是用來(lái)管理數(shù)據(jù)庫(kù)的計(jì)算機(jī)系統(tǒng),通過(guò)使用 DBMS,多個(gè)用戶可以安全、簡(jiǎn)單

    2024年02月20日
    瀏覽(28)
  • MySQL基礎(chǔ)篇——MySQL數(shù)據(jù)庫(kù)客戶端連接,數(shù)據(jù)模型,SQL知識(shí)

    MySQL基礎(chǔ)篇——MySQL數(shù)據(jù)庫(kù)客戶端連接,數(shù)據(jù)模型,SQL知識(shí)

    作者簡(jiǎn)介:一名云計(jì)算網(wǎng)絡(luò)運(yùn)維人員、每天分享網(wǎng)絡(luò)與運(yùn)維的技術(shù)與干貨。? ?座右銘:低頭趕路,敬事如儀 個(gè)人主頁(yè):網(wǎng)絡(luò)豆的主頁(yè)?????? 目錄 前言 一.客戶端連接MySQL 二. 數(shù)據(jù)模型 1.關(guān)系型數(shù)據(jù)庫(kù)(RDBMS) 2.數(shù)據(jù)模型 三.SQL 1.SQL通用語(yǔ)法 2.SQL分類 3.數(shù)據(jù)庫(kù)操作 1). 查

    2024年02月06日
    瀏覽(25)
  • mysql+sqlyog的超詳細(xì)完整安裝+數(shù)據(jù)庫(kù)基礎(chǔ)知識(shí)

    mysql+sqlyog的超詳細(xì)完整安裝+數(shù)據(jù)庫(kù)基礎(chǔ)知識(shí)

    地址:https://dev.mysql.com/downloads/mysql/5.5.html#downloads 注冊(cè)或登錄Oracle賬戶下載 復(fù)制到文件路徑至bin的到 此電腦——高級(jí)系統(tǒng)設(shè)置——高級(jí)——環(huán)境變量—— 點(diǎn)下面的path 新建粘貼路徑即可 一路確定 環(huán)境配置完成后,打開(kāi)文件夾,創(chuàng)建一個(gè)新的文件后綴名為 .ini 的 my.ini空白文

    2024年02月06日
    瀏覽(19)
  • 找工作所需數(shù)據(jù)庫(kù)基礎(chǔ)知識(shí)與實(shí)際操作(以MySQL為例)

    第一章、數(shù)據(jù)庫(kù)原理概述 1.1.2 數(shù)據(jù)庫(kù)、數(shù)據(jù)字典、數(shù)據(jù)庫(kù)管理系統(tǒng)、數(shù)據(jù)庫(kù)系統(tǒng) 1. 數(shù)據(jù)庫(kù)(DB)--- (1)概念:按一定結(jié)構(gòu)組織并長(zhǎng)期存儲(chǔ)在計(jì)算機(jī)內(nèi)的、在邏輯上保持一致的、可共享的大量相關(guān)數(shù)據(jù)的集合---存儲(chǔ)數(shù)據(jù)倉(cāng)庫(kù) (2)屬性:較小的冗余度、較高的數(shù)據(jù)獨(dú)立性、易

    2024年02月05日
    瀏覽(92)
  • mysql數(shù)據(jù)庫(kù)面試題基礎(chǔ)知識(shí),Hadoop之MapReduce04,騰訊java面試流程

    mysql數(shù)據(jù)庫(kù)面試題基礎(chǔ)知識(shí),Hadoop之MapReduce04,騰訊java面試流程

    該方法的執(zhí)行過(guò)程比較復(fù)雜,我們慢慢來(lái)分析,首先來(lái)看下簡(jiǎn)化的時(shí)序圖 3.1waitForCompletion public boolean waitForCompletion(boolean verbose ) throws IOException, InterruptedException, ClassNotFoundException { // 判斷任務(wù)的狀態(tài),如果是DEFINE就提交 if (state == JobState.DEFINE) { submit(); } if (verbose) { // 監(jiān)聽(tīng)并且

    2024年04月14日
    瀏覽(33)
  • MySQL-創(chuàng)建和管理表:基礎(chǔ)知識(shí)、創(chuàng)建和管理數(shù)據(jù)庫(kù)、創(chuàng)建表、修改表、重命名表、刪除表、清空表、拓展

    MySQL-創(chuàng)建和管理表:基礎(chǔ)知識(shí)、創(chuàng)建和管理數(shù)據(jù)庫(kù)、創(chuàng)建表、修改表、重命名表、刪除表、清空表、拓展

    注:此為筆者學(xué)習(xí)尚硅谷-宋紅康MySQL的筆記,其中包含個(gè)人的筆記和理解,僅做學(xué)習(xí)筆記之用,更多詳細(xì)資訊請(qǐng)出門左拐B站:尚硅谷!!! 1.1 一條數(shù)據(jù)存儲(chǔ)的過(guò)程 存儲(chǔ)數(shù)據(jù)是處理數(shù)據(jù)的第一步 。只有正確地把數(shù)據(jù)存儲(chǔ)起來(lái),我們才能進(jìn)行有效的處理和分析。否則,只能是一團(tuán)

    2024年04月11日
    瀏覽(95)
  • 數(shù)據(jù)庫(kù)基礎(chǔ)知識(shí)

    名稱 描述 舉例 DDL 數(shù)據(jù)定義語(yǔ)言 create(創(chuàng)建)、alter(修改)、drop(刪除)、rename(重命名)、truncate(清空) DML 數(shù)據(jù)操作語(yǔ)言 insert(添加)、delete(刪除)、update(修改)、select(查詢) DCL 數(shù)據(jù)控制語(yǔ)言 commit(提交)、rollback(撤銷)、grant(賦予權(quán)限)、revoke(回收

    2024年02月09日
    瀏覽(93)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包