一、總 結
- 事務是一個最小的不可再分的工作單元。 一個事務對應一套完整的業務邏輯。
- 事務管理機制的作用 —— 通過保證一系列數據操作過程的完整性,來保障數據的安全性。
- 使用事務的前提條件 —— 數據庫管理系統必須使用支持事務的存儲引擎。
- MySQL中默認采用InnoDB存儲引擎,默認采用【自動提交模式】來管理事務。
- 事務機制的經典使用場景 —— 處理“銀行賬戶之間的轉賬操作" 。
- 事務只和DML語句有關,只有DML語句的出現才存在事務管理。
- 開啟事務管理的標志 —— DML語句的執行。
- 結束事務管理的標志 —— TCL語句的執行。
- 事務管理的四大特性 —— ACID : 【原子性、一致性、隔離性、持久性】
- 事務之間由低到高的四個隔離級別 —— 【讀未提交、讀已提交、可重復讀、串行化讀】
- 可以把一系列要執行的操作稱為事務。而事務管理就是管理這些操作要么完全執行,要么完全不執行。反映在SQL中就是,事務只和DML語句有關。通常,一個完整的業務需要通過執行批量的DML語句之后,進行統一提交事務,才能達到效果。
二、解 析
(一)銀行轉賬業務的分析
銀行轉賬過程是一個完整的業務,最小的單元,不可再分,也就是說銀行轉賬業務是一個完整的事務。
1) t_act 賬戶表中的數據如下:
2)需求:賬戶“1001”要 轉賬給 “1002”賬戶。
該一系列“轉賬”操作,應當會導致數據庫表中的相關數據發生修改。
假設轉賬金額是500元。
就應該執行下列兩條DML語句:
update t_act set balance = 1000.0 where actno = ‘act-001’;
update t_act set balance = 500.0 where actno = ‘act-002’;
3)分析:
- 以上兩條DML語句必須同時成功或者同時失敗,因為它為最小業務單元,不可拆分;
- 當第一條DML語句執行成功之后,並不能立馬將底層數據庫中的第一個賬戶的數據修改,應該只是將操作記錄了一下,這個記錄是在內存中完成的。
- 當第二條DML語句執行成功之后,底層數據庫文件中的數據需要完成同步。
- 若第二條DML語句執行失敗,將清空所有的歷史操作記錄
4)技術(機制):
要完成以上功能,那必須借助mysql數據庫的“事務“機制 transaction。
在mysql中並不是所有的數據存儲引擎都支持事務管理的,只有 Innodb數據存儲支持事務管理。且默認采用自動提交事務方式。
(即執行DML語句時,默認自動提交事務。)
在mysql中,,常用的3種存儲引擎?
1)myISam (不支持事務)
2)InnoDB (MySql數據庫默認使用是InnoDB存儲引擎。該存儲引擎支持事務。)
3)memory (不支持事務)
2. )一個完整的業務需要批量的DML語句(insert、update、delete)共同完成。
比如:銀行賬戶轉賬 業務
從A賬戶向B賬戶轉賬10000 , 需要執行兩條update語句:
update t_act set balance = balance - 10000 where actno = 'act-001';
update t_act set balance = balance + 10000 where actno = 'act-002';
以上兩條DML語句必須同時成功,或者同時失敗,不允許出現一條成功,一條失敗。
要想保證以上的兩條DML語句同時成功或者同時失敗,那么就需要使用數據庫的“事務機制”。
思考:假設所有的業務都能使用1條DML語句搞定,還需要事務機制嗎?
該情況不需要使用到事務。
但實際開發中,通常一事務【業務】需要多條DML語句共同聯合完成。
事務只和DML語句有關系;當執行DML語句時,其實就是開啟了一個事務。
或者說 只有DML語句(insert/ delete/ update)中才存在事務。
因為它們這三個語句都是和數據庫表當中的“數據”相關的。
以上所描述的批量DML語句共有多少DML語句,這個和業務邏輯有關系。
業務邏輯不同,則DML語句的個數不同。
4. )事務可以保證多個操作的原子性。即,事務的存在就是為了保證數據的完整性,安全性。*
事務可以保證多個操作的原子性:要么全部成功,要么全部失敗。
對於數據庫來說,事務保證批量的DML要么全部成功,要么全部失敗
5. )【TCL】語句是和事務相關的語句 **
rollback 或commit 的執行,標志着事務的結束。
4.事務管理?
可以把一系列要執行的操作稱為事務。
而事務管理就是管理這些操作要么完全執行,要么完全不執行。
經典例子:
A要給B轉錢,首先A賬戶錢減少了,但由於數據庫突然斷電,導致無法給B賬戶加錢。
然后由於丟失數據,B不承認收到A的錢;
在這里事務就是確保加錢和減錢兩個都完全執行或完全不執行,如果加錢失敗,那么不會發生減錢。
0)-手動開啟事務管理的命令
start transaction
這行命令作用是:
【start transaction命令的作用】:
在mysql開啟了“自動提交”模式的狀態下,關閉了事務的自動提交機制,對接下來要執行的DML語句進行手動開啟事務管理。
手動開啟事務管理之后,從此mysql不再將DML語句執行出來的結果立即更新到表中。而是會記錄到事務的日志中。只有開發者手動地進行commit提交成功之后,mysql才會將DML執行結果同步到數據庫的表中。
1)-事務開啟的標志
任何一條DML語句執行,都標志事務的開啟。
2)-事務結束的標志
commit 或 rollback的執行,都標志着事務的結束。
1)事務提交 操作
語法:commit ———— 事務成功的結束。
會將所有的DML語句操作記錄 和 底層硬盤文件中數據進行一次同步。
2)事務回滾 操作
語法:rollback ———— 事務失敗的結束。
會將所有的DML語句操作記錄全部清空。
回滾會清掉開始事務管理之后寫到事務日志中的內容,即恢復到開啟事務管理之前。
注意:回退操作只是回退"寫"的內容,對於普通的讀表select語句不能回退。
3)-事務管理的意義
保證數據操作的完整性,安全性。
4)-注意事項
在事務進行過程中,未結束之前,DML語句是不會修改底層數據庫文件中的數據。只是將歷史操作在內存中記錄一下。只有在事務結束,而且是成功結束(提交)的時候,才會修改底層硬盤文件中的數據。
只能回滾 insert、delete和update語句,不能回滾select語句(回滾select沒有任何意義)。
對於create、drop、alter這些語句也無法回滾。
當 commit 或 rollback 語句執行后,事務會自動關閉(將來的更改會隱含提交)。
(二)事務管理的四大特性
1.原子性(Atomicity)
事務的整個操作是一個整體,不可以分割,要么全部成功,要么全部失敗。
事務是最小的工作單元,不可再分。
只有兩種結果:成功 或 失敗
2.一致性(Consistency)
指的是事務操作的前后,數據表中的數據沒有變化。
事務必須保證多條DML語句同時成功或者同時失敗。
3.隔離性(Isolation)
事務之間的操作是相互隔離不受影響的。
事務A與事務B之間具有隔離。一個事務不會影響其他的事務運行。
4.持久性(Durability)
數據一旦提交,不可改變,永久的改變數據表數據
持久性說的是最終數據必須持久化到硬盤文件中,事務才算成功的結束。
只有事務成功提交的情況下,才有持久性。
在事務完成后,該事務對數據庫所做的更改將持久化地保存在數據庫中,事務才算成功的結束。且不會
被回滾。
(三)事務管理的提交模式
自動提交模式的狀態用於決定新事務 如何啟動 以及 何時啟動。
自動提交模式的開啟或關閉,可以通過服務器變量AUTOCOMMIT來控制。
1-啟用 自動提交模式
如果自動提交模式被啟用,則單條DML語句將缺省地開始一個新的事務。
如果該語句執行成功,事務將自動提交,並永久地保存該語句的執行結果。
如果語句執行失敗,事務將自動回滾,並取消該語句的執行結果。
在自動提交模式下,仍可使用start transaction語句來顯式地啟動事務。這時,一個事務仍可包含多條語句,直到這些語句被統一提交或回滾。
2-禁用 自動提交模式
如果禁用自動提交,事務可以跨越多條語句。
在這種情況下,事務可以用COMMIT和ROLLBACK語句來顯式地提交或回滾。
三、MySql中的事務管理
(一)MySQL中事務采用自動提交模式
默認情況下,mysql的事務管理采用的是自動提交模式:DML語句的只要執行一條DML,就開啟了事務,並提交這次事務;於是執行結果會立馬同步到到數據表中。
0.查詢事務管理狀態
show variables like 'autocommit';
查詢結果 —— ON值,代表自動提交。
查詢結果 —— OFF值,代表 不是自動提交。 需要手動執行 commit;
1.關閉自動提交事務
(1)使用命令
在自動提交模式開啟的情況下,關閉事務的自動提交,手動開啟事務。
step1:
start transaction; // 該SQL命令含義:關閉了事務的自動提交機制,手動開啟事務管理。
step2:
執行若干條DML語句。
step3:
commit; // 進行事務的提交
start transaction命令的作用:
在mysql開啟了“自動提交”模式的狀態下,關閉了事務的自動提交機制,對接下來要執行的DML語句進行手動開啟事務管理。
手動開啟事務管理之后,從此mysql不再將DML語句執行出來的結果立即寫到表中,而是會記錄到事務的日志中。只有開發者手動地進行commit提交成功之后,mysql才會將DML執行結果同步到數據庫的表中。
(2)修改變量值
MySql中事務的自動提交模式。該方式只對當前會話有效 (將off值改為on,則為"開啟")
set autocommit=off;
或
set autocommit=0;
或
set session autocommit = off
關閉后自動提交事務之后,則需要commit來執行每一條語句,相當於手動開啟了事務管理。
不過注意的是set autocommit針對的是會話變量,所以這個設置只在此次會話連接中生效。
2.開啟自動提交事務
set autocommit=on;
或
set autocommit=1;
(二)事務間的隔離性
1.引發的相關問題
隔離性是事務管理的四大特性之一,事務之間存在隔離級別。
事務的隔離級別決定了事務之間可見的級別。
理論上隔離級別包括4個: 低 ——高
因事務之間的隔離性引發的相關問題
當多個客戶端並發地訪問同一個表時,可能出現下面的一致性問題:
(1)臟讀取
一個事務開始讀取了某行數據,但是另外一個事務已經更新了此數據但沒有能夠及時提交,這就出現了臟讀取(Dirty Read)。
(2)不可重復讀
在同一個事務中,同一個讀操作對同一個數據的前后兩次讀取產生了不同的結果,這就是不可重復讀(Non-repeatable Read)。
(3)幻像讀
幻像讀(Phantom Read)
是指在同一個事務中以前沒有的行,由於其他事務的提交而出現的新行數據。
2.事務的隔離級別
InnoDB 存儲引擎支持這四種事務的隔離級別。用以控制事務所做的修改,並將修改通告至其它並發的事務:
1-read uncommitted 讀未提交
2- read committed 讀已提交
3- repeatable read 可重復讀
4- serializable 串行化(序列化)
(1)read uncommitted
對方事務A還沒有提交,我們當前事務B可以讀取到對方未提交的數據。 這里讀到的數據,叫“臟數據”或 “臟讀 Dirty Read”
讀未提交存在臟讀(Dirty Read)現象:表示讀到了臟的數據。
1) 事務A和和事務B,事務A未提交的數據,事務B可以讀取。(允許一個事務可以看到其他事務未提交的修改。)
2) 這里讀取到的數據可以叫做“臟數據”或“臟讀 Dirty Read”
3) 讀未提交隔離級別最低,這種級別一般叧在理論上存在,數據庫默認隔離級別一般都高於該隔離級別;
(2)read committed
1) 事務A和事務B,事務A提交的數據,事務B才可讀取到;(允許一個事務只能看到其他事務已經提交的修改,未提交的修改是不可見的。)
2) 該隔離級別高於“讀未提交”級別,解決了: 臟讀現象。
3) 換句話說:對方事務提交之后的數據,當前事務才可讀取到。
4) 該隔離級別可以避免臟數據;
5) 該隔離級別能夠導致“不可重復讀取”
6) Oracle數據庫管理系統默認隔離級別為“讀已提交”
(Oracle數據庫支持 READ COMMITTED 和 SERIALIZABLE這兩種事務隔離級別。)
(3)repeatable read
1) 事務A和事務B,事務A提交之后的數據,事務B還是讀取不到。事務B只能讀取到,事務B開啟事務時刻表中的數據。
2) 事務B是可重復讀到數據的。(確保如果在一個事務中執行兩次相同的SELECT語句,都能得到相同的結果,不管其他事務是否提交這些修改。 (銀行總賬))
3) 這種隔離級別高於“讀已提交”。
4) 換句話說,對方提交之后的數據,還是讀取不到。
5) 這種隔離級別可以避免“臟讀和不可重復讀”,達到“重復讀取”;
6) MySQL數據庫管理系統默認隔離級別為:可重復讀
7) 這種隔離級別解決了:不可重復讀問題,達到了“重復讀取”。
該隔離級別存在的問題是:讀取到的數據是幻象。
(4)serializable
序列化讀/串行化讀
1 ) 事務A和事務B,事務A在操作數據庫表中數據的時候,事務B叧能排隊等待;(將一個事務與其他事務完 全地隔離。 )
2) 這種事務隔離級別一般很少使用,吞吐量太低,用戶體驗不好;效率低。需要事務排隊。
3) 事務A和事務B不再並發;避免了“幻想讀”,每一次讀取都是數據庫表中真實的記錄。
3.事務隔離級別的作用范圍
- 會話級(session):只對當前會話有效
- 全局級(global) : 對所有會話有效
(1.1)查當前會話隔離級別
select @@tx_isolation;
或
select @@session.tx_isolation;
(1.2)查看全局隔離級別
select @@global.tx_isolation;
(2.1)設置會話隔離級別
set transaction isolation level 隔離級別類型 ;
或
set session transaction isolation level 隔離級別類型 ;
(2.2)設置全局隔離級別
set global transaction isolation level 隔離級別類型;
4-設置服務器缺省隔離級別
(1)靜態設置:修改配置
關閉服務器,修改my.ini配置文件
在 my.ini 文件中的[mysqld]下面添加:
transaction-isolation = 隔離級別類型
(2)動態設置:使用命令
在運行的服務器中通過命令方式,動態設置
set [global/session] transaction isolation level 隔離級別類型;
四、JDBC中的事務
1-JDBC中的事務默認采用自動提交機制
即 ,只要執行任意一條DML語句,JDBC則會自動提交一次事務。
但是在實際的業務當中,通常都是使用N條DML語句共同聯合才能完成的。必須保證他們這些DML語句在同一個事物中同時成功或者同時失敗。
典型的案例:銀行轉賬業務
2-代碼演示 “銀行轉賬”業務
分析:采用JDBC中默認的自動提交事務機制,會對該業務實現過程中產生的影響。以及給出解決方案。
代碼編號:**《Jdbc_Transaction/演示銀行轉賬業務》**
3-事務+【行級鎖】的使用
1)悲觀鎖/行級鎖
事務必須排隊執行。被選中鎖住的數據不允許被並發修改。
使用方法:select語句后面添加for update即可。如:
使用場景:
在實際開發中,在查詢某張表數據時,為了保障數據的真實性,可以使用【行級鎖】
(使用方法:在select語句之后添加for update)將需要的這些數據進行鎖住。於是,別的線程開啟的事務將無法對這些數據進行修改。
select ename,job,sal from emp where job = 'manager' for update;
這行語句的意思:工作崗位是manager的這些員工數據被鎖定。(行級鎖) 當前事務未結束時,這些數據被鎖住了。其他的事務無法對這些被鎖住的數據進行修改操作。
2)樂觀鎖
支持並發,事務也無需排隊。但是會多一個版本號的概念。
多線程並發時,也可以對某條數據進行修改。
執行原理:
假設:開啟事務1時,讀取到數據的版本號是1.1。同時開啟事務2,讀取到數據的版本號也是1.1。
事務1先對數據進行了修改,修改之后發現版本號依舊是1.1,和它最初讀取到的版本號一致(說明沒有其他的事務對數據進行了修改)。於是提交事務修改數據。版本號將會變更為1.2。
事務2再進行修改數據,修改之后准備提交時,發現數據的版本號是1.2。和它最初讀取到的版本號不一致(說明有其他的事務對數據進行了修改)。於是會執行回滾操作。
| ename | job | sal | version |
| ----- | ------- | ---- | ------- |
| james | manager | 8000 | 1.1 |
3)代碼演示
結合Debug工具查看效果
涉及到兩個程序
1-演示程序開啟一個事務.java
2-該程序演示修改被鎖定的記錄.java
《Jdbc_Transaction/事務+行級鎖的使用》
五、MyBatis中的事務
九.其他
鎖機制
在事務操作一個表時,如果使用索引來取值,那么會鎖定到對應行;
如果沒有使用索引來取值,那么會鎖定整個表。鎖定之后其他連接無法操作指定行或表。
回滾點
作用:回滾點可以指定rollback回退的位置。
> 比如:現在打了100條命令,發現第81打錯了,如果回滾到打了81命令之前一點而不是回滾到開啟事務之前就可以節省下很多時間。
創建回滾點: savepoint 回滾點名;
回滾到回滾點: rollback to 回滾點名;
注意事項:回滾點在事務管理關閉(rollback或commit之后)之后失效,**不能在事務之外使用回滾點。
單機事務
分布式事務
即數據庫不是一個。是數據庫集群。分布方式的。
一個數據庫不夠
北京的數據庫 轉到 南京的數據庫。
保證這兩數據庫的事務都成功,才能成功。
