zno2

spring 事务传播属性 (propagation)

propagation   /ˌprɒpəˈɡeɪʃn/  传播

资料:

https://www.cnblogs.com/zno2/p/4767565.html

https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html#tx-propagation

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html#REQUIRED

 

注意测试前将jdbc事务自动提交设置为true

 

先说验证结论

黄色字代表有异常,绿背景代表提交事务,白背景代表回滚

 REQUIRED     Support a current transaction, create a new one if none exists. (可以视作同一个事务)

Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction’s chance to actually commit (as you would expect it to).

 

 NESTED        Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else. (和required 不同之处在于inner不影响outer,inner可以独立回滚,但是outter回滚皆回滚)

 

SUPPORTS    Support a current transaction, execute non-transactionally if none exists. (传播时同required,不支持非传播但是也不抛异常)

 

 MANDATORY       Support a current transaction, throw an exception if none exists.(强制,传播时同required,不支持非传播会抛异常)

 

 REQUIRES_NEW       Create a new transaction, and suspend the current transaction if one exists. (最简单,完全独立)

 

 NOT_SUPPORTED       Execute non-transactionally, suspend the current transaction if one exists. (不抛异常,不支持)

 

 NEVER      Execute non-transactionally, throw an exception if a transaction exists. (均不支持,且传播时抛异常)

 

 

 

关键测试代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.zno.txtest.mapper.FooMapper;
import cn.zno.txtest.tx.Tx;
import cn.zno.txtest.tx.TxA;


@SpringBootApplication
@org.springframework.stereotype.Controller
@ImportResource(locations= {"classpath*:spring/root/public-*.xml" ,"classpath:spring/root/private-*.xml"})
public class FooApplication {

    public static void main(String[] args) {
        SpringApplication.run(FooApplication.class, args);
    }
    
    @Autowired
    private FooMapper fooMapper;

    @Autowired
    private Tx tx;
    @Autowired
    private TxA txA;
    

    @GetMapping(path="test")
    @ResponseBody
    public String test() {
        String s = "";
        s+= test0(false,false) + "<br>";
        s+= test0(false,true) + "<br>";
        s+= test0(true,true) + "<br>";
        s+= test0(true,false) + "<br>";
        return s;
    }
    
    private String test0(Boolean throwa, Boolean throwb) {
        tx.init();
        System.out.println("初始化完成");
        try {
            txA.deleteA(throwa, throwb);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("事务测试完毕");
        Long a = fooMapper.selectA();
        Long b = fooMapper.selectB();
        System.out.println();
        boolean rollbackA = true;
        if(a == null) {
            rollbackA = false;
        }
        
        boolean rollbackB = true;
        if(b == null) {
            rollbackB = false;
        }
        
        String result = "A:%s,B:%s";
        
        return throwa + "\t" + throwb + "\t" +  String.format(result, rollbackA?"回滚":"提交", rollbackB?"回滚":"提交");
    }
}

 

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

public interface FooMapper {

    @Update("delete from a")
    int deleteA();
    
    @Update("delete from b")
    int deleteB();
    
    @Insert("insert a values (#{id})")
    int initA(@Param("id") long id);
    
    @Insert("insert b values (#{id})")
    int initB(@Param("id") long id);
    
    @Select("select id from a")
    Long selectA();
    
    @Select("select id from b")
    Long selectB();
}

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.zno.txtest.mapper.FooMapper;

@Service
public class Tx {
    
    @Autowired
    private FooMapper fooMapper;

    @Transactional
    public void init() {
        fooMapper.deleteA();
        fooMapper.deleteB();
        fooMapper.initA(1);
        fooMapper.initB(2);
    }
}

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.zno.txtest.mapper.FooMapper;

@Service
public class TxA {
    
    @Autowired
    private FooMapper fooMapper;
    
    @Autowired
    private TxB txB;
    
    @Transactional
    public void deleteA(boolean throwa, boolean throwb) {
        fooMapper.deleteA();
        
        try {
            txB.deleteB(throwb);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        
        if(throwa) {
            throw new RuntimeException("异常a");
        }
    }
}

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cn.zno.txtest.mapper.FooMapper;

@Service
public class TxB {
    
    @Autowired
    private FooMapper fooMapper;
    
//    @Transactional
    @Transactional(propagation=Propagation.MANDATORY)
    public void deleteB(boolean throwb) {
        fooMapper.deleteB();
        
        if(throwb) {
            throw new RuntimeException("异常b");
        }
    }
}

 

 小结:

上面是4个对传播的立场及态度

传播时,supports、mandatory与required 相同

required_new 最简单,完全独立

 nested 自己可以单独回滚不会影响outter,但是outter回滚会连带nested一起回滚

 

 

 

项目见:svn   txtest

posted on 2023-06-01 14:24  zno2  阅读(89)  评论(0编辑  收藏  举报

导航