@Transactional失效场景

上一篇:事务的两种形式

@Transactional介绍

@Transactional注解底层使用的是动态代理来进行实现的

Transactional注解可以作用在接口、类、类方法

  • 作用接口: 不推荐,因为这只有在使用基于接口的代理时它才会生效
  • 作用于类:表示该类的所有public方法都配置相同的事务属性信息
  • 作用于类方法:只能用于public方法上。注意:如果类于类方法都配置了@Transactional,类方法事务会覆盖类事务

propagation属性

propagation代表事务的传播行为,默认值为Propagation.REQUIRED

  • Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则新创建事务(也就是说如果A方法和B方法都添加了注解,默认传播模式下,A方法调用B方法,会将两个方法事务合并为一个)
  • Propagation.SUPPORTS:如果当前存在事务,则加入,如果不存在,则以非事务形式运行
  • Propagation.MANDATORY:如果当前存在事务,则加入事务,如果不存在事务,则抛异常
  • Propagation.REQUIRES_NEW:重新创建一个事务,如果当前存在事务,暂停当前事务(如果A方法默认为Propagation.REQUIRED模式,B方法为Propagation.REQUIRES_NEW,在A方法中调用B方法,A方法抛出异常后,B方法不会回滚,因为Propagation.REQUIRES_NEW会暂停A方法的事务)
  • Propagation.NOT_SUPPORTED:以非事务方法运行,如果当前存在事务,暂停当前事务
  • Propagation.NESTED :和 Propagation.REQUIRED 效果一样

isolation属性

isolation事务的隔离级别,默认值为Isolation.DEFAULT

  • Isolation.DEFAULT:使用底层数据库默认的隔离级别
  • Isolation.READ_UNCOMMITTED
  • Isolation.READ_COMMITTED
  • Isolation.REPEATABLE_READ
  • Isolation.SERIALIZABLE

timeout属性

timeout事务的超时时间,默认值:-1,如果超过该时间限制事务还未完成,则自动回滚

readOnly属性

readOnly指定事务是否为只读事务,默认值为false,它的存在是为了让那些不需要事务的方法被排除掉,例如:读取数据,可以设置为readOnly为true

rollbackFor属性

用于指定能够触发事务回滚的异常类型,可以指定多个异常类型

noRollbackFor属性

指定的异常类型,不回滚事务,可以指定多个异常类型

@Transactional失效场景

  1. @Transactional注解应用在非public方法上


    image.png

    之所以会失效式因为在Spring AOP代理时,如上图所示 TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法,获取Transactional 注解的事务配置信息。


    image.png
  2. propagation 配置错误
    其中这三种会存在以非事务形式运行
    TransactionDefinition.PROPAGATION_SUPPORTS、TransactionDefinition.PROPAGATION_NOT_SUPPORTED、
    TransactionDefinition.PROPAGATION_NEVER;
    Propagation.REQUIRES_NEW也会存在事务失效的情况,见上述Propagation.REQUIRES_NEW的举例描述

  3. rollbackFor配置错误


    image.png

Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor属性。
希望自定义的异常可以进行回滚@Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class
若在目标方法中抛出的异常是 rollbackFor 指定的异常的子类,事务同样会回滚。

  1. 同一个类中方法间的调用
    A调用本类中的B方法(不论B时public或者private),A没有声明事务,而B方法有。外部调用A方法后,方法B的事务不会起作用。
    这是由于使用Spring AOP代理造成的,因为只有当前事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
//@Transactional 
@GetMapping("/test") 
private Integer A() throws Exception { 
    CityInfoDict cityInfoDict = new CityInfoDict(); 
    cityInfoDict.setCityName("2"); 
    /** * B 插入字段为 3的数据 */ 
    this.insertB();
 /** * A 插入字段为 2的数据 */ 
    int insert = cityInfoDictMapper.insert(cityInfoDict);
    return insert; 
} 
@Transactional() 
public Integer insertB() throws Exception {
    CityInfoDict cityInfoDict = new CityInfoDict();
    cityInfoDict.setCityName("3");
    cityInfoDict.setParentCityId(3);
    return cityInfoDictMapper.insert(cityInfoDict);
 }
  1. 异常被你的catch“吃了”
@Transactional 
private Integer A() throws Exception {
    int insert = 0; 
    try { 
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setCityName("2");
        cityInfoDict.setParentCityId(2); 
        /** * A 插入字段为 2的数据 */
        insert = cityInfoDictMapper.insert(cityInfoDict);
        /** * B 插入字段为 3的数据 */ 
        b.insertB(); 
    } catch (Exception e) {
        e.printStackTrace();
    }
 }

如果B方法发生了异常,而A方法catch住了B方法的异常,那么这个事务不能正常回滚
会抛出:org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

因为当B方法中抛出了一个异常后,B标识当前事务需要rollback。但是A中由于收到铺货了这个异常并进行了处理,A任务当前事务应该可以正常commit。此时前后不一致,抛出UnexpectedRollbackException

Spring事务时在调用业务方法之前开始的,业务方法执行完毕之后才执行commit or rollback,事务是否执行取决于是否抛出RuntimeException,如果抛出了并且未catch到的话,事务就会回滚。

  1. 数据库不支持事务
    mysql数据库默认使用支持事务的innodb引擎,一旦切换为不支持事务的myisam,那么事务就会失效

原文链接:https://baijiahao.baidu.com/s?id=1661650900351466294&wfr=spider&for=pc

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容