Spring核心系列之Spring中的事務

Spring核心系列之Spring中的事務

Hello,你們好,前面兩篇文章給你們分享了Spring AOP,今天就趁熱打鐵,給你們分享一下,Spring中的事務,事務這個事,其實在國內一些小公司,通常都會忽略的,尤爲是不少網站,設計不到錢的系統,不會在意這個東西,事務不回滾形成的結果無非就是髒數據,髒改等後果。由於做者之前待過的一個房產網站,根本就不在意這個事務,有問題就有問題了,反正用戶也沒充錢在網站上。呵呵。今天仍是和你們分享一下這個Spring的事務,由於這個東西算是Spring 內部使用AOP最好的一個體現,體現了AOP思想,OK,文章結構:html

  1. Spring boot 中的事務
  2. Spring事務中的事務屬性

1. Spring boot 中的事務

看到Spring boot,不少人確定感受是被忽悠了,爲何說講Spring事務,這又來Spring boot搞事情。用過Spring boot的小夥伴其實都知道,這兩個沒什麼大的區別,筆者這裏使用Spring boot來演示,徹底是爲何了簡便。由於搭一個Spring傳統的ssm三件套工程可能要花費5分鐘,而搭建一個Spring boot的"ssm"工程,就是鼠標點一點的事。並且開啓事務也是一個註解的事。因此,老鐵們,對不住了,這一篇用Spring boot和你們演示Spring的事務,這裏我給一個傳送門,是傳統項目的事務,你們能夠參考下:java

廢話說下,直接上Spring boot代碼:mysql

@SpringBootApplication
@EnableTransactionManagement  
public class TestTxApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestTxApplication.class, args);
	}
}
複製代碼

@EnableTransactionManagement 表示開啓事務!spring

@Component
public class PersonService {
    @Autowired
    private PersonMapper personMapper;

    @Transactional
    public void testTx(){
        //該操做會成功
        personMapper.update();
        //該操做會報異常
        personMapper.update2();
    }
}
複製代碼

這是一個Service,內部的personMapper是一個dao接口,持久化用的mybatissql

@Mapper
public interface PersonMapper {
    //更改某條記錄
    @Update("update user_info set user_name='123' where user_id='1' ")
    Long update();
    //user_info2這個表不存在。會報異常
    @Update("update user_info2 set user_name='123' where user_id='1' ")
    Long update2();
}
複製代碼

演示的效果應該是:數據庫

  1. 當調用PersonService的testTx()時,因爲開啓了事務,因此update2報異常時,應該會回滾。update1的操做不會被寫入數據庫。
  2. 去掉testTx()上面的@Transactional註解,再作試驗,發現雖然報異常,但數據仍是update了。

具體我就不演示了 。你們能夠看到,在Spring boot中開啓事務就是一個註解的事 。具體的內部使用什麼trancationManagement根本不用管,Spring boot內部會根據pom中引入的持久層框架自動注入。真是開發神器!數組

而後我說下底層原理:Spring事務其實就是Spring AOP,底層建立動態代理對象,在代碼的開頭結尾封裝了開啓事務和事務回滾操做。用過JDBC原生代碼的更應該清楚了,都是顯示在代理裏commit和rollback的。而後一大堆try catch..mybatis

2. Spring事務中的事務屬性

上面的代碼雖然簡單,也能應對大部分的場景,但仍是有一些問題的,好比,有些異常開發者知道,而且想人爲的控制,"拋出某類異常,不要回滾".這樣的問題。這就引出了,事務屬性這個概念,事務屬性一般由事務的傳播行爲,事務的隔離級別,事務的超時值和事務只讀標誌組成。 這些屬性都是在使用@Transactional能夠指定的,我給一張表格: app

而後把這些屬性講一講:框架

2.1 isolation

事務的隔離界別:使用@Transactional的Isolation屬性能夠指定事務的隔離級別。但事務的隔離級別是由底層的數據庫實現的,並非由Spring來實現。

  1. ISOLATION_DEFAULT ,這是默認的隔離級別,使用數據庫默認的事務隔離級別.另外四個與JDBC的隔離級別相對應.
  2. ISOLATION_READ_UNCOMMITTED 這是事務最低的隔離級別,它充許別外一個事務能夠看到這個事務未提交的數據。這種隔離級別會產生髒讀,不可重複讀和幻像讀。
  3. ISOLATION_READ_COMMITTED 保證一個事務修改的數據提交後才能被另一個事務讀取。另一個事務不能讀取該事務未提交的數據。這種事務隔離級別能夠避免髒讀出現,可是可能會出現不可重複讀和幻像讀。
  4. ISOLATION_REPEATABLE_READ這種事務隔離級別能夠防止髒讀,不可重複讀。可是可能出現幻像讀。它除了保證一個事務不能讀取另外一個事務未提交的數據外,還保證了不可重複讀。
  5. ISOLATION_SERIALIZABLE 這是花費最高代價可是最可靠的事務隔離級別。事務被處理爲順序執行。除了防止髒讀,不可重複讀外,還避免了幻像讀。

通常的數據庫默認提供的是READ_COMMITTED隔離級別,如sqlserver2000;Mysql默認提供的是REPEATABLE_READ;

好了,結論給你們說完了,而後解釋一下上面提到的 髒讀,不可重複讀和幻象讀的概念。

髒讀:

  1. Mary的原工資爲1000,財務人員將Mary的工資改成了8000,但未提交事務
  2. 與此同時,Mary正在讀取本身的工資.Mary發現本身的工資變爲了8000,歡天喜地! (髒讀)
  3. 而財務發現操做有誤,而回滾了事務,Mary的工資又變爲了1000.

不可重複讀:在一個事務中先後兩次讀取的結果並不致,致使了不可重複讀。

  1. 在事務1中,Mary 讀取了本身的工資爲1000,操做並無完成 .
  2. 在事務2中,這時財務人員修改了Mary的工資爲2000,並提交了事務.
  3. 在事務1中,Mary 再次讀取本身的工資時,工資變爲了2000.

幻想讀:

  1. 目前工資爲1000的員工有10人。
  2. 事務1,讀取全部工資爲1000的員工。共讀取10條記錄 .
  3. 這時另外一個事務向employee表插入了一條員工記錄,工資也爲1000
  4. 事務1再次讀取全部工資爲1000的員工,共讀取到了11條記錄,這就產生了幻像讀。

好了,事務的隔離級別就講完了,通常仍是採用數據庫默認的,像mysql的REPEATABLE_READ,可以避免髒讀和不可重複讀。

2.2 propagation

  1. REQUIRED:表示業務方法須要在一個事務中處理,若是業務方法執行時已經在一個事務中,則加入該事務,不然從新開啓一個事務。這也是默認的事務傳播行爲;
  2. NOT_SUPPORTED:聲明業務方法不須要事務,若是業務方法執行時已經在一個事務中,則事務被掛起,等方法執行完畢後,事務恢復進行;

其餘的傳播行爲省略,基本不用,通常的傳播行爲也是使用默認的:REQUIRED

2.3 rollbackFor rollbackForClassName noRollbackFor norollbackForClassName

Transactional的異常控制,默認是Check Exception不回滾,unCheck Exception回滾,rollbackFor 和noRollbackFor 配置也許不會含蓋全部異常,對於遺漏的按照Check Exception 不回滾,unCheck Exception回滾.

使用@Transactional註解的noRollbackFor和rollbackFor屬性能夠改變默認的行爲:

  • 如:@Transactional(rollbackFor=Exception.class)可使checked異常發生時,數據庫操做也rollback,@Transactional(noRollbackFor=RuntimeException.class)可使unchecked異常發生時也提交數據庫操做。

也可使用noRollbackForClassName、rollbackForClassName屬性來指定一個異常類名的String數組來改變默認的行爲。

好了,事務屬性大體就這麼多了,其餘一些就是比較簡單的了,看名字就知道啥意思,伸手就用的東西,而後再提一下,@Transactional只能被應用到public方法上, 對於其它非public的方法,若是標記了@Transactional也不會報錯,但方法沒有事務功能..

老實說,通常事務屬性配置的比較少,通常都是直接@Transactional加上就完事了。不多配置一些屬性。尤爲是那個事務傳播行爲,在平常的業務裏,不多有食物嵌套的狀況,因此我就是點了一點,沒有展開。通常使用默認就能夠了。

結語

好了,Spring的事務使用層面給你們算是分享完了,在Spring boot裏想使用事務簡單的有點可怕。因此我就採用Spring boot了。其實傳統的SSM項目也很簡單,無非就是在xml文件裏配置下tranclationManagement..而後Spring 事務的底層是Spring AOP,把jdbc的事務代碼嵌入了進去。Over,Have a good day!

相關文章
相關標籤/搜索