【數據庫】事務、ACID、數據庫的隔離級別、髒讀、不可重複、幻讀

事務的思想:

很多複雜的事物要分步進行(複雜的東西經常要拆分),但它們組成一個整體,要麼整體生效,要麼整體失效。這種思想反映到數據庫上,就是多個SQL語句,要麼所有執行成功,要麼所有執行失敗。
數據庫事務:

數據庫事務(Database Transaction)是指將一系列數據庫操作當作一個邏輯處理單元的操作,**這個單元中的數據庫操作要麼完全執行,要麼完全不執行。**通過將一組相關操作組合爲一個邏輯處理單元,可以簡化 錯誤恢復,並使應用程序更加可靠。
一個邏輯處理單元要成爲事務,必須滿足ACID屬性。(原子性Atomic、一致性Consistency、隔離性Isolation和持久性Durabiliy),所謂的ACID含義如下。

原子性(Atomicity):表示組成一個事務的多個數據庫操作是一個不可分割的原子單元,只有所有的操作執行成功,整個事務才提交,事務中任何一個數據庫操作失敗,已經執行的任何操作都必須撤銷,讓數據庫返回到初始狀態。也就是一個事務內的操作,要麼全部執行成功,要麼全部執行不成功。
一致性(Consistency):事務執行後,數據庫所處的狀態和它的業務規則是一致的,即數據不會被破壞。如轉賬業務,無論事務執行成功與否,參與轉賬的兩個賬號餘額之和應該是不變的(兩人的錢總額是不變的。)。
隔離性(Isolation):在併發數據操作時,不同的事務擁有各自的數據空間,它們的操作不會對對方產生干擾。準確地說,並非要求做到完全無干擾,數據庫規定了多種事務隔離級別,不同隔離級別對應不同的干擾程度,**隔離級別越高,數據一致性越好,但併發性越弱。**每個事務獨立運行。在併發環境中,併發的事務是互相隔離的,互不影響。
持久性(Durability):一旦事務提交成功後,事務中所有的數據操作都必須被持久化到數據庫中,即使提交事務後,數據庫馬上崩潰,在數據庫重啓時,也必須保證能夠通過某種機制恢復數據。也就是事務一旦提交後,數據庫中的數據必須被永久地保存下來。

1、事務:
事務是表示一組操作要麼同時成功,要麼同時失敗,而且事務與事務之間是獨立。
事務有ACID的特性。
(1)原子性(2)一致性(3)隔離性(4)持久性

銀行轉賬

張三-》李四轉賬500元
張三原來的餘額是1000元,
李四原來的餘額是0元。

(1)張三賬戶-500
(2)李四賬戶+500

一致性:要麼張三還是1000,李四是0
	    要麼張三現在是500,李四是500
		
張三-500成功了,要給李四+500時,發現李四的賬號異常,那麼要回滾,還原剛剛張三-500的操作。
如果都成功了,就提交。

事務:
網購,下訂單

(1)創建訂單--》訂單表中要添加記錄
(2)記錄訂單明細--》訂單明細表中要添加訂單都買了什麼
(3)商品表修改-->庫存量修改,銷量增量	

2、
mysql默認是自動提交事務,一句SQL是一個事務,執行成功一句就提交一句。

手動開始事務,取消自動提交。
方式一:
set autocommit = false;
這次客戶端連接,在你恢復自動提交之前,
接下來所有的SQL執行都必須手動提交了,否則就不生效。

這個設置只管一個連接,和其他的連接(登錄)無關。
set autocommit = false;
… 都是需要手動提交的。
set autocommit = true;

當只是部分的SQL需要構成事務,手動提交,而其他SQL還是想要自動提交的。
那麼我們選擇方式二。

方式二:
start transaction;
… 一個事務
commit;或rollback;

start transaction;
… 另一個事務
commit;或rollback;

… 自動提交

3、事務的隔離級別
同一個庫的同一個表同一個記錄,對於多個事務來說,就是共享數據。
多個事務被多個線程同時執行時,那麼共享數據就會線程安全問題。

隔離級別低 實時性、速度
針對不同安全級別的要求,設置了不同的隔離級別:
(1)read uncommitted:可以讀取未提交的
事務1,可以讀取到事務2已經修改,但是還沒正式提交的數據
會出現髒讀、不可重複讀、幻讀
(2)read committed:讀取已提交的數據
事務1,只能讀取到事務2已提交的數據
會出現不可重複讀、幻讀
(3)repeatable READ:
原來:會出現幻讀
現在:幻讀也可以避免
行鎖
(4)Serializable
所有問題都可以避免。
表鎖
鎖的級別不一樣 性能低
幾種問題:
(1)髒讀現象
事務1對某個記錄進行修改,還未提交。事務2就看到了。
那麼這個被事務1修改還未提交的數據就是髒數據。

如何避免髒讀,把事務隔離級別設置爲(2)(3)(3)都可以避免。

(2)不可重複的
事務1對某個表進行修改,已經提交。
但是事務2,在事務1提交之前,查詢了一下這個記錄,
在事務1提交之後,又查詢了一下這個記錄,
對於事務2來說,出現了不可重複讀的現象。
在同一個事務中,前後兩次對同一個記錄的讀取發現不一樣。
如果想要避免不可重複讀,那麼需要設置隔離級別爲(3)(4)

(3)幻讀
事務1給某個表增加了新的記錄,或者刪除了某個表的記錄。(記錄數有變化)
並且提交了。
事務2,在事務1提交之前,查詢了這個表
在事務1提交之後,查詢了這個表
對於事務2來說,前後兩次的記錄數不一樣。好比出現幻覺一樣。多出或少了記錄。多了少了數據

如果想要避免幻讀,那麼需要設置隔離級別爲(4)。
但是mysql在5.0之後,升級了。在隔離級別(3)的時候,就可以避免幻讀了。

對於同時運行的多個事務, 當這些事務訪問數據庫中相同的數據時, 如果沒有采取必要的隔離機制, 就會導致各種併發問題:

  • 髒讀: 對於兩個事務 T1, T2, T1 讀取了已經被 T2 更新但還沒有被提交的字段。 之後, 若 T2 回滾, T1讀取的內容就是臨時且無效的。

  • 不可重複讀: 對於兩個事務T1, T2, T1 讀取了一個字段, 然後 T2 更新了該字段。 之後, T1再次讀取同一個字段, 值就不同了。

  • 幻讀: 對於兩個事務T1, T2, T1 從一個表中讀取了一個字段, 然後 T2 在該表中插入了一些新的行。 之後, 如果 T1 再次讀取同一個表, 就會多出幾行。

  • 數據庫事務的隔離性:數據庫系統必須具有隔離併發運行各個事務的能力, 使它們不會相互影響, 避免各種併發問題。

  • **一個事務與其他事務隔離的程度稱爲隔離級別。**數據庫規定了多種事務隔離級別, 不同隔離級別對應不同的干擾程度, 隔離級別越高, 數據一致性就越好, 但併發性越弱。

  • Oracle 支持的 2 種事務隔離級別:READ COMMITED, SERIALIZABLE。 Oracle 默認的事務隔離級別爲: READ COMMITED 。

  • Mysql 支持 4 種事務隔離級別。 Mysql 默認的事務隔離級別爲: REPEATABLE READ。在mysql中REPEATABLE READ的隔離級別也可以避免幻讀了。

4、如何查詢當前連接是什麼隔離級別
mysql默認的隔離級別是:
±----------------+
| @@tx_isolation |
±----------------+
| REPEATABLE-READ |
±----------------+

用戶要查看的話:select @@tx_isolation;

5、如何修改當前連接的隔離級別
set tx_isolation = ‘read-uncommitted’;
set tx_isolation = ‘read-committed’;
set tx_isolation = ‘REPEATABLE-READ’;
set tx_isolation = ‘serializable’;

在MySql中設置隔離級別

  • 每啓動一個 mysql 程序, 就會獲得一個單獨的數據庫連接。每個數據庫連接都有一個全局變量 @@tx_isolation, 表示當前的事務隔離級別.
  • 查看當前的隔離級別: SELECT @@tx_isolation;
  • 查看全局的隔離級別: SELECT @@global.tx_isolation;
  • 設置當前 mySQL 連接的隔離級別:
set tx_isolation ='repeatable-read';
  • 設置數據庫系統的全局的隔離級別:
set global tx_isolation ='read-committed';

注意:這裏的隔離級別中間是減號,不是下劃線。

SQL:
1、DDL
2、DML
3、DCL
事務的commit等是屬於DCL

事務回滾和提交只對insert, update,delete有效。
對create,drop等DDL語句是無效的。





delete from 【數據庫名.]表名稱 【where 條件】;


如果沒有where條件,表示刪除整張表的數據;


truncate 【數據庫名.]表名稱;#刪除整張表的數據,還可以使用這個語句,效率更高,但是它不能回滾
刪除了不能回滾

用delete刪除整張表和用truncate刪除整張表的數據的區別?

(1)truncate速度快

(2)truncate無法回滾

truncate因爲底層是把表drop掉,然後新建了一張空表。

delete因爲底層是一行一行刪數據。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章