您好,登錄后才能下訂單哦!
這篇“java中事務的特性有哪幾種”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“java中事務的特性有哪幾種”文章吧。
Java中事務的特性有四種,原子性、一致性、隔離性、持久性
原子性:如果執行一條sql,底層是默認執行事務的,叫做隱形事務,當執行多條sql語句的時候,多條sql語句不可以進行分割,必須全部一次性執行完成,就是要么全部完成,要么失敗;
一致性:事務完成后,數據狀態保持一致性,能量守恒定律,哈哈哈;
隔離性:多個事務并發訪問數據庫,事務對數據的修改,需要與其他事務進行隔離;
持久性:數據修改完成,數據持久化存儲;
使用JDBC,需要先關閉主動提交事務,然后執行多條SQL語句,然后提交,如果報錯進行回滾事務,在最后啟動自動提交,因為執行1條sql語句的時候,也會開啟事務,叫做隱形事務,默認進行提交,如果關閉了不啟動,以后執行一條SQL也需要顯示顯示事務了;
Connection conn = openConnection(); try { // 關閉自動提交: conn.setAutoCommit(false);// 執行多條SQL語句:insert(); update(); delete();// 提交事務: conn.commit();} catch (SQLException e) { // 回滾事務: conn.rollback();} finally { conn.setAutoCommit(true);conn.close(); }
Mysql隔離級別分為4種:Read Uncommitted(讀取未提交的)、Read Committed(讀取提交的)、Repeatable Red(可重復讀)、Serializaable(串行化)
Isolation Level | 臟讀(Dirty Read) | 不可重復讀(Non Repeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
Read Uncommitted | Yes | Yes | Yes |
Read Committed | - | Yes | Yes |
Repeatable Read | - | - | Yes |
Serializable | - | - | - |
Read Uncommitted是隔離級別最低的一種事務級別。在這種隔離級別下,一個事務會讀到另一個事務更新后但未提交的數據,如果另一個事務回滾,那么當前事務讀到的數據就是臟數據,這就是臟讀(Dirty Read)。
mysql> select * from students;+----+-------+| id | name | +----+-------+| 1 | Alice | +----+-------+1 row in set (0.00 sec)
然后,分別開啟兩個MySQL客戶端連接,按順序依次執行事務A和事務B:
當事務A執行完第3步時,它更新了id=1
的記錄,但并未提交,而事務B在第4步讀取到的數據就是未提交的數據。
隨后,事務A在第5步進行了回滾,事務B再次讀取id=1
的記錄,發現和上一次讀取到的數據不一致,這就是臟讀。
可見,在Read Uncommitted隔離級別下,一個事務可能讀取到另一個事務更新但未提交的數據,這個數據有可能是臟數據。
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE students SET name = 'Bob' WHERE id = 1; | |
4 | SELECT * FROM students WHERE id = 1; | |
5 | ROLLBACK; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
在Read Committed隔離級別下,一個事務可能會遇到不可重復讀(Non Repeatable Read)的問題。
不可重復讀是指,在一個事務內,多次讀同一數據,在這個事務還沒有結束時,如果另一個事務恰好修改了這個數據,那么,在第一個事務中,兩次讀取的數據就可能不一致。
我們仍然先準備好students
表的數據:
mysql> select * from students;+----+-------+| id | name | +----+-------+| 1 | Alice | +----+-------+1 row in set (0.00 sec)
然后,分別開啟兩個MySQL客戶端連接,按順序依次執行事務A和事務B:
當事務B第一次執行第3步的查詢時,得到的結果是Alice
,隨后,由于事務A在第4步更新了這條記錄并提交,所以,事務B在第6步再次執行同樣的查詢時,得到的結果就變成了Bob
,因此,在Read Committed隔離級別下,事務不可重復讀同一條記錄,因為很可能讀到的結果不一致。
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 1; | |
4 | UPDATE students SET name = 'Bob' WHERE id = 1; | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
在Repeatable Read隔離級別下,一個事務可能會遇到幻讀(Phantom Read)的問題。
幻讀是指,在一個事務中,第一次查詢某條記錄,發現沒有,但是,當試圖更新這條不存在的記錄時,竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現了。
我們仍然先準備好students
表的數據:
mysql> select * from students;+----+-------+| id | name | +----+-------+| 1 | Alice | +----+-------+1 row in set (0.00 sec)
然后,分別開啟兩個MySQL客戶端連接,按順序依次執行事務A和事務B:
事務B在第3步第一次讀取id=99
的記錄時,讀到的記錄為空,說明不存在id=99
的記錄。隨后,事務A在第4步插入了一條id=99
的記錄并提交。事務B在第6步再次讀取id=99
的記錄時,讀到的記錄仍然為空,但是,事務B在第7步試圖更新這條不存在的記錄時,竟然成功了,并且,事務B在第8步再次讀取id=99
的記錄時,記錄出現了。
可見,幻讀就是沒有讀到的記錄,以為不存在,但其實是可以更新成功的,并且,更新成功后,再次讀取,就出現了。
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 99; | |
4 | INSERT INTO students (id, name) VALUES (99, 'Bob'); | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 99; | |
7 | UPDATE students SET name = 'Alice' WHERE id = 99; | |
8 | SELECT * FROM students WHERE id = 99; | |
9 | COMMIT; |
Serializable是最嚴格的隔離級別。在Serializable隔離級別下,所有事務按照次序依次執行,因此,臟讀、不可重復讀、幻讀都不會出現。
雖然Serializable隔離級別下的事務具有最高的安全性,但是,由于事務是串行執行,所以效率會大大下降,應用程序的性能會急劇降低。如果沒有特別重要的情景,一般都不會使用Serializable隔離級別。
如果沒有指定隔離級別,數據庫就會使用默認的隔離級別。在MySQL中,如果使用InnoDB,默認的隔離級別是Repeatable Read。
在啟動類上添加注解 @EnableTransactionManagement ,
在執行事務的方法上面使用 @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)設置隔離界別與事務傳播。默認就是REQUIRED;
Spring的聲明式事務為事務傳播定義了幾個級別,默認傳播級別就是REQUIRED,它的意思是,如果當前沒有事務,就創建一個新事務,如果當前有事務,就加入到當前事務中執行。
SUPPORTS
:表示如果有事務,就加入到當前事務,如果沒有,那也不開啟事務執行。這種傳播級別可用于查詢方法,因為SELECT語句既可以在事務內執行,也可以不需要事務;
MANDATORY
:表示必須要存在當前事務并加入執行,否則將拋出異常。這種傳播級別可用于核心更新邏輯,比如用戶余額變更,它總是被其他事務方法調用,不能直接由非事務方法調用;
REQUIRES_NEW
:表示不管當前有沒有事務,都必須開啟一個新的事務執行。如果當前已經有事務,那么當前事務會掛起,等新事務完成后,再恢復執行;
NOT_SUPPORTED
:表示不支持事務,如果當前有事務,那么當前事務會掛起,等這個方法執行完成后,再恢復執行;
NEVER
:和NOT_SUPPORTED
相比,它不但不支持事務,而且在監測到當前有事務時,會拋出異常拒絕執行;
NESTED
:表示如果當前有事務,則開啟一個嵌套級別事務,如果當前沒有事務,則開啟一個新事務。
以上就是關于“java中事務的特性有哪幾種”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。