Spring事務(wù)隔離級(jí)別簡(jiǎn)介及實(shí)例解析
本文研究的主要是Spring事務(wù)隔離級(jí)別(solation level)介紹及例子,具體如下。
當(dāng)兩個(gè)事務(wù)對(duì)同一個(gè)數(shù)據(jù)庫的記錄進(jìn)行操作時(shí),那么,他們之間的影響是怎么樣的呢?這就出現(xiàn)了事務(wù)隔離級(jí)別的概念。數(shù)據(jù)庫的隔離性與并發(fā)控制有很大關(guān)系。數(shù)據(jù)庫的隔離級(jí)別是數(shù)據(jù)庫的事務(wù)特性ACID的一部分。ACID,即原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)。Spring的事務(wù)隔離級(jí)別有四個(gè):READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE。還有一個(gè),是數(shù)據(jù)庫默認(rèn)的隔離級(jí)別DEFAULT,MySQL默認(rèn)是REPEATABLE_READ。
下面來具體看看。
READ_UNCOMMITTED
顧名思義,READ_UNCOMMITTED意思是,一個(gè)事務(wù)可以讀取到另一個(gè)事務(wù)未提交的事務(wù)記錄。換句話說,a transaction can read the data that is still uncommitted by other transactions。這是Spring事務(wù)最弱的隔離級(jí)別。見下面的圖,事務(wù)A開啟,寫入一條記錄,這時(shí)候,事務(wù)B讀入數(shù)據(jù),讀到了這條記錄,但是,之后事務(wù)A回滾。因此,事務(wù)B讀到的數(shù)據(jù)不是有效的(the database is in an invalid state)。這種情況稱為臟讀(dirty read)。除了臟讀的問題,READ_UNCOMMITTED還可能出現(xiàn)non-repeatable read(不可重復(fù)讀)和phantom read(幻讀)的問題。

READ_COMMITTED
READ_COMMITTED隔離級(jí)別表明,一個(gè)事務(wù)只能讀取到已經(jīng)提交的記錄,不能讀取到未提交的記錄。換句話說,a transaction can only read the committed data, and it can't read the uncommitted data.因此,dirty read的情況不再發(fā)生,但可能會(huì)出現(xiàn)其他問題。見下圖。

在事務(wù)A兩次讀取的過程之間,事務(wù)B修改了那條記錄并進(jìn)行提交。因此,事務(wù)A前后兩次讀取的記錄不一致。這個(gè)問題稱為non-repeatable read(不可重復(fù)讀)。(兩次讀取的記錄不一致,重復(fù)讀取就會(huì)發(fā)現(xiàn)問題。)
除了non-repeatable read的問題,READ_COMMITTED還可能發(fā)生phantom read的問題。
REPEATABLE_READ
REPEATABLE_READ意思是,一個(gè)事務(wù)可以多次從數(shù)據(jù)庫讀取某條記錄,而且多次讀取的那條記錄都是一致的,相同的。這個(gè)隔離級(jí)別可以避免dirty read和non-repeatable read的問題,但可能發(fā)生phantom read的問題。如下圖。

事務(wù)A兩次從數(shù)據(jù)庫讀取一系列記錄,期間,事務(wù)B插入了某條記錄并提交。事務(wù)A第二次讀取時(shí),會(huì)讀取到事務(wù)B剛剛插入的那條記錄。在事務(wù)期間,事務(wù)A兩次讀取的一系列記錄不一致,這個(gè)問題稱為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ì)帶來性能的下降。
DEFAULT
MySQL默認(rèn)是REPEATABLE_READ。
例子
下面,我們看一個(gè)例子。在數(shù)據(jù)庫mysql里開啟一個(gè)事務(wù),不提交。然后,另一個(gè)事務(wù)讀取記錄。
剛開始,數(shù)據(jù)庫里的記錄,如圖

接下來,在數(shù)據(jù)庫mysql中開啟事務(wù)A,并插入一條記錄。

在service的業(yè)務(wù)類的事務(wù)屬性配置為READ_UNCOMMITTED。
@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è)試類
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é)果如下:

可見,這個(gè)事務(wù)讀取到了未提交的數(shù)據(jù)。
這時(shí)候,將mysql中開啟的事務(wù)A回滾。
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)專題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
相關(guān)文章
springboot實(shí)現(xiàn)異步調(diào)用@Async的示例
這篇文章主要介紹了springboot實(shí)現(xiàn)異步調(diào)用@Async的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
基于MockMvc進(jìn)行springboot調(diào)試(SpringbootTest)
這篇文章主要介紹了基于MockMvc進(jìn)行springboot調(diào)試(SpringbootTest),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
Java實(shí)現(xiàn)將每日新聞添加到自己博客中
這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)將每日新聞添加到自己博客中并發(fā)送到微信群中,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12
Spring Boot使用AOP在指定方法執(zhí)行完后執(zhí)行異步處理操作
這篇文章主要介紹了Spring Boot使用AOP在指定方法執(zhí)行完后執(zhí)行異步處理操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06
SpringBoot結(jié)合SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能
這篇文章主要介紹了SpringBoot + SpringSecurity 實(shí)現(xiàn)圖形驗(yàn)證碼功能,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05
springboot內(nèi)嵌Tomcat安全漏洞修復(fù)方式
針對(duì)CVE-2020-1938漏洞,建議升級(jí)Tomcat至安全版本以避免受影響,影響版本包括:Apache Tomcat 9.x小于9.0.31、Apache Tomcat 8.x小于8.5.51、Apache Tomcat 7.x小于7.0.100及Apache Tomcat 6.x,2024-10-10
mybatis查詢結(jié)果返回至實(shí)體類的示例代碼
這篇文章主要介紹了mybatis查詢結(jié)果返回至實(shí)體類的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

