spring 事务传播属性 (propagation)
propagation /ˌprɒpəˈɡeɪʃn/ 传播
资料:
https://www.cnblogs.com/zno2/p/4767565.html
注意测试前将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