本文研究的主要是spring事務(wù)隔離級(jí)別(solation level)介紹及例子,具體如下。
當(dāng)兩個(gè)事務(wù)對(duì)同一個(gè)數(shù)據(jù)庫(kù)的記錄進(jìn)行操作時(shí),那么,他們之間的影響是怎么樣的呢?這就出現(xiàn)了事務(wù)隔離級(jí)別的概念。數(shù)據(jù)庫(kù)的隔離性與并發(fā)控制有很大關(guān)系。數(shù)據(jù)庫(kù)的隔離級(jí)別是數(shù)據(jù)庫(kù)的事務(wù)特性acid的一部分。acid,即原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)。spring的事務(wù)隔離級(jí)別有四個(gè):read_uncommitted
、read_committed
、repeatable_read
和serializable
。還有一個(gè),是數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別default
,mysql默認(rèn)是repeatable_read
。
下面來(lái)具體看看。
read_uncommitted
顧名思義,read_uncommitted
意思是,一個(gè)事務(wù)可以讀取到另一個(gè)事務(wù)未提交的事務(wù)記錄。換句話說(shuō),a transaction can read the data that is still uncommitted by other transactions。這是spring事務(wù)最弱的隔離級(jí)別。見(jiàn)下面的圖,事務(wù)a開(kāi)啟,寫(xiě)入一條記錄,這時(shí)候,事務(wù)b讀入數(shù)據(jù),讀到了這條記錄,但是,之后事務(wù)a回滾。因此,事務(wù)b讀到的數(shù)據(jù)不是有效的(the database is in an invalid state)。這種情況稱(chēng)為臟讀(dirty read)。除了臟讀的問(wèn)題,read_uncommitted
還可能出現(xiàn)non-repeatable read
(不可重復(fù)讀)和phantom read
(幻讀)的問(wèn)題。
read_committed
read_committed
隔離級(jí)別表明,一個(gè)事務(wù)只能讀取到已經(jīng)提交的記錄,不能讀取到未提交的記錄。換句話說(shuō),a transaction can only read the committed data, and it can't read the uncommitted data.因此,dirty read的情況不再發(fā)生,但可能會(huì)出現(xiàn)其他問(wèn)題。見(jiàn)下圖。
在事務(wù)a兩次讀取的過(guò)程之間,事務(wù)b修改了那條記錄并進(jìn)行提交。因此,事務(wù)a前后兩次讀取的記錄不一致。這個(gè)問(wèn)題稱(chēng)為non-repeatable read(不可重復(fù)讀)。(兩次讀取的記錄不一致,重復(fù)讀取就會(huì)發(fā)現(xiàn)問(wèn)題。)
除了non-repeatable read的問(wèn)題,read_committed
還可能發(fā)生phantom read的問(wèn)題。
repeatable_read
repeatable_read意思是,一個(gè)事務(wù)可以多次從數(shù)據(jù)庫(kù)讀取某條記錄,而且多次讀取的那條記錄都是一致的,相同的。這個(gè)隔離級(jí)別可以避免dirty read和non-repeatable read的問(wèn)題,但可能發(fā)生phantom read的問(wèn)題。如下圖。
事務(wù)a兩次從數(shù)據(jù)庫(kù)讀取一系列記錄,期間,事務(wù)b插入了某條記錄并提交。事務(wù)a第二次讀取時(shí),會(huì)讀取到事務(wù)b剛剛插入的那條記錄。在事務(wù)期間,事務(wù)a兩次讀取的一系列記錄不一致,這個(gè)問(wèn)題稱(chēng)為phantom read。
serializable
serializable是spring最強(qiáng)的隔離級(jí)別。事務(wù)執(zhí)行時(shí),會(huì)在所有級(jí)別上加鎖,比如read和write時(shí)都會(huì)加鎖,仿佛事務(wù)是以串行的方式進(jìn)行的,而不是一起發(fā)生的。這會(huì)防止dirty read、non-repeatable read和phantom read的出現(xiàn),但是,會(huì)帶來(lái)性能的下降。
default
mysql默認(rèn)是repeatable_read
。
例子
下面,我們看一個(gè)例子。在數(shù)據(jù)庫(kù)mysql里開(kāi)啟一個(gè)事務(wù),不提交。然后,另一個(gè)事務(wù)讀取記錄。
剛開(kāi)始,數(shù)據(jù)庫(kù)里的記錄,如圖
接下來(lái),在數(shù)據(jù)庫(kù)mysql中開(kāi)啟事務(wù)a,并插入一條記錄。
在service的業(yè)務(wù)類(lèi)的事務(wù)屬性配置為read_uncommitted
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@transactional (isolation=isolation.read_uncommitted) public class accountservice { private accountdao accountdao; public accountdao getaccountdao() { return accountdao; } public void setaccountdao(accountdao accountdao) { this .accountdao = accountdao; } public void transfer(string from, string to, double money) { accountdao.outmoney(from, money); accountdao.inmoney(to, money); } public void readalluser() { list<account> accounts = accountdao.getalluser(); for (account account : accounts) { system.out.println(account); } } } |
運(yùn)行下面的測(cè)試類(lèi)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.chris.service; import static org.junit. assert .*; import org.junit.test; import org.junit.runner.runwith; import org.springframework.beans.factory.annotation.autowired; import org.springframework.test.context.contextconfiguration; import org.springframework.test.context.junit4.springjunit4classrunner; @runwith (springjunit4classrunner. class ) @contextconfiguration ( "classpath:applicationcontext.xml" ) public class readallusertest { @autowired private accountservice accountservice; @test public void test() { accountservice.readalluser(); } } |
結(jié)果如下:
可見(jiàn),這個(gè)事務(wù)讀取到了未提交的數(shù)據(jù)。
這時(shí)候,將mysql中開(kāi)啟的事務(wù)a回滾。
1
|
mysql> rollback; |
再次運(yùn)行程序,結(jié)果為
account [name=michael, money=1000.0]
account [name=jane, money=1000.0]
account [name=kate, money=1000.0]
總結(jié)
以上就是本文關(guān)于spring事務(wù)隔離級(jí)別簡(jiǎn)介及實(shí)例解析的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專(zhuān)題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
原文鏈接:http://blog.csdn.net/csdn_so_nice/article/details/54290665