事務(Transaction)管理機制



一、總    結


  1. 事務是一個最小的不可再分的工作單元。 一個事務對應一套完整的業務邏輯。
  2. 事務管理機制的作用 —— 通過保證一系列數據操作過程的完整性,來保障數據的安全性。
  3. 使用事務的前提條件    ——    數據庫管理系統必須使用支持事務的存儲引擎。
  4. MySQL中默認采用InnoDB存儲引擎,默認采用【自動提交模式】來管理事務。
  5. 事務機制的經典使用場景    ——    處理“銀行賬戶之間的轉賬操作" 。
  6. 事務只和DML語句有關,只有DML語句的出現才存在事務管理。
  7. 開啟事務管理的標志 —— DML語句的執行。
  8. 結束事務管理的標志 —— TCL語句的執行
  9. 事務管理的四大特性 —— ACID : 【原子性、一致性、隔離性、持久性】
  10. 事務之間由低到高的四個隔離級別 —— 【讀未提交、讀已提交、可重復讀、串行化讀】
  11. 可以把一系列要執行的操作稱為事務。而事務管理就是管理這些操作要么完全執行,要么完全不執行。反映在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之后)之后失效,**不能在事務之外使用回滾點。

單機事務

分布式事務
 即數據庫不是一個。是數據庫集群。分布方式的。  一個數據庫不夠
北京的數據庫  轉到 南京的數據庫。
保證這兩數據庫的事務都成功,才能成功。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM