SpringBoot新增事務管理

但你沒有#發表於2020-11-30

在啟動類上加入@EnableTransactionManagement

package com.yl.j2005.spc.emp.providerserver;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;

@SpringBootApplication
@EnableEurekaClient
@MapperScan(basePackages = "com.yl.j2005.spc.emp.providerserver.mapper")
@EnableTransactionManagement   //加入事務管理
public class SpcEmpProviderServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpcEmpProviderServerApplication.class, args);
    }

}

再所需加入事務的資料庫管理操作上加入 @Transactional(propagation= Propagation.REQUIRED,isolation = Isolation.DEFAULT,rollbackFor=Exception.class)


propagation引數,Propagation型別(列舉),預設值為Propogation.REQUIRED,支援的值有REQUIRED、MANDATORY、NESTED、NEVER、NOT_SUPPORTED、REQUIRE_NEW、SUPPORTS。

//propagation值得是事務的傳播性
//所謂事務傳播性,就是被呼叫者的事務與呼叫者的事務之間的關係。舉例說明。
//in A.java
Class A {
    @Transactional(propagation=propagation.REQUIRED)
    public void aMethod {
        B b = new B();
        b.bMethod();
    }
}
 
//in B.java
Class B {
    @Transactional(propagation=propagation.REQUIRED)
    public void bMethod { //something }
}
在上面這個例子中,傳播性被設為了REQUIRED,注意,這是預設值,也即不進行該引數配置等於配置成REQUIRED。

  REQUIRED的含義是,支援當前已經存在的事務,如果還沒有事務,就建立一個新事務。在上面這個例子中,假設呼叫aMethod前不存在任何事務,那麼執行aMethod時會自動開啟一個事務,而由aMethod呼叫bMethod時,由於事務已經存在,因此會使用已經存在的事務(也就是執行aMethod之前建立的那個事務)。

  對於這樣的配置,如果bMethod過程中發生異常需要回滾,那麼aMethod中所進行的所有資料庫操作也將同時被回滾,因為這兩個方法使用了同一個事務。

  MANDATORY的含義是,支援當前已經存在的事務,如果還沒有事務,就丟擲一個異常。如果上例中aMethod的傳播性配置為MANDATORY,我們就無法在沒有事務的情況下呼叫aMethod,因此,傳播性為MANDATORY的方法必定是一個其他事務的子事務,當邏輯上獨立存在沒有意義或者可能違反資料、事務完整性的時候,就可以考慮設定這樣的傳播性設定。

  NESTED的含義是,在當前事務中建立一個巢狀事務,如果還沒有事務,那麼就簡單地建立一個新事務。

  REQUIRES_NEW的含義是,掛起當前事務,建立一個新事務,如果還沒有事務,就簡單地建立一個新事務。

  請注意以上兩者的區別,大多數情況下一上兩種傳播性行為是類似的,不過在事務回滾的問題上,以上兩者有很大的區別。

  首先,REQUIRES_NEW會建立一個與原事務無關的新事務,儘管是由一個事務呼叫了另一個事務,但卻沒有父子關係。

  如果bMethod的傳播性是REQUIRES_NEW,而丟擲了一個異常,則bMethod一定會被回滾,而如果aMethod捕獲並處理了這個bMethod丟擲的異常,那麼aMethod仍有可能成功提交。當然,如果aMethod沒有處理這個異常,那麼aMethod也會被回滾。

  如果aMethod在bMethod完成後出現了異常,那麼bMethod已經提交而無法回滾,只有aMethod被回滾了。

  而對於NESTED,雖然也會建立一個新事務,但是這個事務與呼叫者是有父子關係的相互依存的。

  如果bMethod的傳播性是NESTED,而丟擲了一個異常,事務的回滾行為與REQUIRES_NEW是一致的。

  但是如果aMethod在bMethod完成後出現了異常,bMethod同樣也會被回滾。因為事實上,EJB中沒有對於NESTED傳播性的類似實現,NESTED並不是真正啟動了一個事務,而是開啟了一個新的savepoint。

  NEVER的含義很簡單,就是強制要求不在事務中執行,如果當前存在一個事務,則丟擲異常,因此如果bMethod傳播性是NEVER,則一定丟擲異常。

  NOT_SUPPORTED的含義是,強制不在事務中執行,如果當前存在一個事務,則掛起該事務。

  SUPPORTS的含義是,支援當前事務,如果沒有事務那麼就不在事務中執行。SUPPORTS傳播性的邏輯含義比較模糊,因此一般是不推薦使用的。

isolation引數—事務的隔離級別,Isolation型別(列舉),預設值為Isolation.DEFAULT,支援的值有DEFAULT、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。
在這裡插入圖片描述

timeout引數,int型別,事務的超時時間,預設值為-1,即不會超時。
readOnly引數,boolean型別,true表示事務為只讀,預設值為false。
rollbackFor引數,Class<? extends Throwable>[]型別,預設為空陣列。如果配置了以後,丟擲了指定異常或者其子類異常則回滾!

rollbackForClassName引數,String[]型別,預設為空陣列。
noRollbackFor引數,Class<? extends Throwable>[]型別,預設為空陣列。
noRollbackForClassName引數,String[]型別,預設為空陣列。

我配置的事務

Controller層

@RequestMapping(value = "updateemp",method = RequestMethod.PUT)
    public ActionResult updateEmp(@RequestBody EmpQualification empQualification){
        System.out.println("empQualification = " + empQualification);
        try {
            boolean result=empService.updateEmp(empQualification);
            return new ActionResult(200,"update ok",null);
        }catch (Exception e){
            e.printStackTrace();
            log.error("新增失敗,事務回滾");
        }return new ActionResult(201,"update false", null);

    }

Service層

 @Transactional(propagation= Propagation.REQUIRED,isolation = Isolation.DEFAULT,rollbackFor=Exception.class)
    @Override
    public boolean updateEmp(EmpQualification empQualification) {

        Integer i=empMapper.updateEmp(empQualification);
        if(i!=0){
            return true;
        }else{
            throw new RuntimeException("修改失敗,事務回滾");
        }

    }

dao層

 Integer updateEmp(EmpQualification empQualification);

mapper語句

<update id="updateEmp" parameterType="com.yl.j2005.bean.sto.EmpQualification">
        update emp set em_name=#{emName},
        em_number=#{emNumber},
        em_age=#{emAge},
        em_sex=#{emSex},
        em_birthday=#{emBirthday},
        em_ethnic=#{emEthnic},
        em_tel=#{emTel},
        em_address=#{emAddress},
        em_workspace=#{emWorkspace},
        dept_id=#{deptId},
        group_id=123456 where em_id=#{emId};

        update qualification set em_biye=#{emBiye},em_congye=#{emCongye},em_shanggang#{emShanggang} where em_id=#{emId};
    </update>

這裡要強調的是 如果一次執行多個語句,必須再資料庫連線字串url中新增如下配置

&allowMultiQueries=true
示例
spring.datasource.url=jdbc:mysql://192.168.0.109:3307/spcproject?allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false
//最後的&autoReconnect=true&failOverReadOnly=false是配置允許長時間未訪問資料庫的連線物件可訪問,不會被資料庫當成死連結

相關文章