精华内容
下载资源
问答
  • Java的@Transactional事务回滚

    万次阅读 2019-12-10 13:26:17
    在应用系统调用声明@Transactional 目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 属性配置信息,这个代理对象决定该声明@Transactional 目标方法是否...

    @Transactional 基本原理概述

    在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。

    处理Springboot下提交事务异常,数据库没有回滚的问题

    Spring文档中说道,Spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。

    什么是检查型异常和非检查型异常?

    最简单的判断点有两个:
    1、继承自runtimeException或error的是非检查型异常,而继承自exception的是检查型异常。
    2、对非检查型异常可以不用捕获,而检查型异常必须用try语句块进行处理或者把异常交给上级方法处理,总之就是必须写代码处理它。所以必须service捕获异常,然后再次抛出,这样事务才能生效。

    默认规则:

    1、让检查型异常也回滚,@Transactional(rollbackFor=Exception.class),一般只需添加这个即可

    2、让非检查型异常不回滚,@Transactional(notRollbackFor=RunTimeException.class)

    3、不需要事务管理的(就是只是查询用)方法,@Transactional(propagation=Propagation.NOT_SUPPORTED),或者不添加

    4、手动回滚,TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    例如:

    try {
            String name = (String) list.get(j - 1).get("name");
          } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultUtil.error(500, "文件解析错误");
           }
    

    你需要注意的事

    1.@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能
    2.Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
    3.当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,还是在具体的类上使用 @Transactional 注解比较好。
    4.避免 Spring 的 AOP 的自调用问题:自调用就是方法A内调用本类的另一个加上事务注解的方法B时,方法B中对数据库的操作是不带事务的。

    Spring AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。
    失效原因:
    在这里插入图片描述
    方法one方法two都是public的:

    classA中 ,任意要调用classB的方法,是通过spring代理的方式,那么spring的注解才会生效
    classA中,方法one 调用同class内的方法two,即this调用,spring注解不会生效(例如@Cachable,@Transaction)

    解决方法

    方案一:使用AspectJ代理

    @Service
    public class OrderService {
        private void insert() {
            insertOrder();
        }
    @Transactional
        public void insertOrder() {
            //insert log info
            //insertOrder
            //updateAccount
           }
    }
    

    insertOrder 尽管有@Transactional 注解,但它被内部方法 insert 调用,事务被忽略,出现异常事务不会发生回滚。

    上面的两个问题@Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP 代理造成的。为解决这两个问题,可以使用 AspectJ取代 Spring AOP 代理,但现在有更好的解决方法。

    方案二:利用AopContext.currentProxy()方法获得代理

    方法的意思是尝试返回当前AOP代理。这种做法非常简洁,但是在默认情况下是不起作用的!因为AopContext中拿不到currentProxy,会报空指针。需要一些额外的配置,但不能对所有的注解拦截都有效,这是因为这些注解不是用的AspectJ代理,如果是@Transactional事务注解的话, 则是生效的,具体细节要翻源码了,这里不推荐使用。

    方案三:通过ApplicationContext来获得动态代理对象(推荐)

    @Component
    public class AsyncService implements ApplicationContextAware {
    
        private ApplicationContext applicationContext;
    
        public void async1() {
            System.out.println("1:" + Thread.currentThread().getName());
            // 使用AppicationContext来获得动态代理的bean,然后再执行你调用的方法
            this.applicationContext.getBean(AsyncService.class).async2();
        }
    
        @Async
        public void async2() {
            System.out.println("2:" + Thread.currentThread().getName());
        }
    
        // 注入ApplicationContext
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    
    展开全文
  • 为什么80%码农都做不了架构师?>>> ...

    看一篇博客,觉得写得很不错就copy过来一份,原博客地址在下面。

    TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
    TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
    TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

    参考链接:http://www.cnblogs.com/yepei/p/4716112.html

    https://blog.csdn.net/qq_34552004/article/details/79599275

     

    在记录一个点:

    事物回滚需要区分检查异常和非检查异常(也就是运行时异常)。检查异常例如IOException异常等,在你写代码时编译提示你必须try catch 或向上抛,反正就是必须处理。而运行时异常,就是在运行时的产生异常,就比如/by zero异常。默认检查异常事物是不会进行回滚的,运行时异常才会进行回滚。添加上@Transactional(rollbackFor = Exception.class) 就可以出现异常就全部回滚了。

    参考链接:https://blog.csdn.net/weixin_41485592/article/details/80877665

     

     

     

    转载于:https://my.oschina.net/uwith/blog/3041674

    展开全文
  • 1.开启了@Transactional注解 2.数据库中保存了一条数据,然后下一行代码查询是可以查询到这条数据,但是数据库中没有 原因是:在开启事务后,只有commit事务提交后才可以查询到 ...

    是因为:

    1.开启了@Transactional注解

    2.数据库中保存了一条数据,然后下一行代码查询是可以查询到这条数据的,但是数据库中没有

     

    原因是:在开启事务后,只有commit事务提交后才可以查询到

     

    为了事物一致性,一般情况,都是加上的

    展开全文
  • 本文重点强调使用@Transactional注解时需要注意许多细节,不然你会发现@Transactional总是莫名其妙就失效了。 事务 @Transactional 事务管理是应用系统开发中必不可少一部分。它能保证方法内多个数据

    引言

    在开发过程中,经常需要使用的事务保证业务逻辑一致性。这个时候可以使用到事务管理
    本文重点强调使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional总是莫名其妙的就失效了。

    事务

    @Transactional 事务管理是应用系统开发中必不可少的一部分。它能保证方法内多个数据库操作要么同时成功、要么同时失败。Spring提供了很好事务管理机制,主要分为编程式事务和声明式事务两种。

    • 编程式事务:是指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较强
    try {
        //TODO something
         transactionManager.commit(status);
    } catch (Exception e) {
        transactionManager.rollback(status);
        throw new InvoiceApplyException("异常失败");
    }
    
    • 声明式事务:基于AOP面向切面的,它将具体业务与事务处理部分解耦,代码侵入性很低,所以在实际开发中声明式事务用的比较多。
    @Transactional
    @GetMapping("/test")
    public String test() {
           // todo something
     }
    

    @Transactional介绍

    @Transactional注解可以作用于哪些地方?

    @Transactional 可以作用在接口、类、类方法。

    • 作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。

    • 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。

    • 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效

    @Transactional注有哪些属性?

    propagation属性

    • propagation 代表事务的传播行为,默认值为

    • Propagation.REQUIRED,其他的属性信息如下:

    • Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。( 也就是说如果A方法和B方法都添加了注解,在默认传播模式下,A方法内部调用B方法,会把两个方法的事务合并为一个事务 )

    • Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

    • Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

    • Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。( 当类A中的 a 方法用默认

    • Propagation.REQUIRED模式,类B中的 b方法加上采用

    • Propagation.REQUIRES_NEW模式,然后在 a 方法中调用 b方法操作数据库,然而 a方法抛出异常后,b方法并没有进行回滚,因为Propagation.REQUIRES_NEW会暂停 a方法的事务 )

    • Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。

    • Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。

    • 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;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。

    rollbackFor 属性

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

    noRollbackFor属性**

    noRollbackFor:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。

    @Transactional失效场景

    接下来我们结合具体的代码分析一下哪些场景下,@Transactional 注解会失效。
    1、 @Transactional 应用在非 public 修饰的方法上

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

    protected TransactionAttribute computeTransactionAttribute(Method method,
        Class<?> targetClass) {
            // Don't allow no-public methods as required.
            if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
            return null;
    }
    

    此方法会检查目标方法的修饰符是否为 public,不是 public则不会获取@Transactional 的属性配置信息。

    注意:protected、private 修饰的方法上使用 @Transactional 注解,虽然事务无效,但不会有任何报错,这是我们很容犯错的一点。

    2、@Transactional 注解属性 propagation 设置错误
    这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。

    TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

    3、@Transactional 注解属性 rollbackFor 设置错误

    rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定rollbackFor属性。

    // 希望自定义的异常可以进行回滚
    @Transactional(propagation= Propagation.REQUIRED,rollbackFor= MyException.class
    

    4、同一个类中方法调用,导致@Transactional失效

    开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,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);
        }
    

    5、异常被你的 catch“吃了”导致@Transactional失效

    这种情况是最常见的一种@Transactional注解失效场景,

    @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方法此时try catch了B方法的异常,那这个事务还能正常回滚吗?

    答案:不能!

    会抛出异常:

    org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
    因为当ServiceB中抛出了一个异常以后,ServiceB标识当前事务需要rollback。但是ServiceA中由于你手动的捕获这个异常并进行处理,ServiceA认为当前事务应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的

    UnexpectedRollbackException异常。

    spring的事务是在调用业务方法之前开始的,业务方法执行完毕之后才执行commit or rollback,事务是否执行取决于是否抛出runtime异常。如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。

    在业务方法中一般不需要catch异常,如果非要catch一定要抛出throw new RuntimeException(),或者注解中指定抛异常类型@Transactional(rollbackFor=Exception.class),否则会导致事务失效,数据commit造成数据不一致,所以有些时候try catch反倒会画蛇添足。

    6、数据库引擎不支持事务

    这种情况出现的概率并不高,事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。

    展开全文
  • 主要介绍@Transactional在底层是如何工作。之后文章将介绍:propagation(事务传播)和isolation(隔离性)等属性使用事务使用陷阱有哪些以及如何避免JPA和事务管理很重要一点是JPA本身并不提供任何类型声明...
  • @Transactional(propagation=Propagation.REQUIRED) 2)NOT_SUPPORTED Spring不为当前方法开启事务,相当于没有事务 @Transactional(propagation=Propagation.NOT_SUPPORTED) 3)REQUIRES_NEW 不管是否存在事务,...
  • @Transactionaljava中使用注解形式事务 既然使用@Transactional就要理解什么是事务.下面将会详细介绍. 1:什么是事务? 事务(Transactional) 就是把多个要做操作组合成一个整体.利用事务特性来保证操作...
  • @Transactional 内部调用例子 ?...若同一类中其他没有@Transactional 注解方法内部调用有@Transactional 注解方法,有@Transactional 注解方法事务被忽略,不会发生回滚@Servicepublic class ...
  • @Transactional在main.java的service下是抛出异常回滚 @Transactional在test.java的下是全部回滚,不管成功不成功
  • @transactional 是我们在java 开发中经常用到注解,帮助我们非常方便快捷完成事务管理,尤其在批量处理数据时候,更是重要,最近业务中遇到了这种情况,批量向数据库导入数据,这就会出现excel表中有数据...
  • java异常与@Transactional回滚

    千次阅读 2018-07-03 14:14:47
    概述:java的异常分为Error 和 Exception 。这两类都是接口Throwable 的子类。 异常分类方式: 1.运行时异常 和 非运行时异常 2.可查的异常(checked exceptions)和 不可查的异常(unchecked exceptions) 总结...
  • 在我们开发中很多时候都要用到事务,例如转账、充值等等操作,这些我就不多BB了,于是很多人就选择最简单方式@Transactional注解,但是你真测试过事务异常时候会回滚吗?等生产环境遇到了在来查找原因那就晚...
  • 我正在尝试使用Guice Persist创建一个带有@Transactional注释方法简单服务类:public class TestServiceImpl implements TestService {@Injectprivate Provider entityManager;@Override@Transactionalpublic Long...
  • 主要介绍了Java注解@Transactional事务类内调用不生效问题及解决办法,文中通过示例代码介绍非常详细,对大家学习或者工作具有一定参考学习价值,需要朋友们下面随着小编来一起学习学习吧
  • 以下是AnnotationTransactionAspect中使用切入点:/*** Matches the execution of any public method in a type with the* Transactional annotation, or any subtype of a type with the* Transactional ...
  •   在我们开发中很多时候都要用到事务,例如转账、充值等等操作,这些我就不多BB了,于是很多人就选择最简单方式@Transactional注解,但是你真测试过事务异常时候会回滚吗?等生产环境遇到了在来查找原因那...
  • java异常与@Transactional

    2019-11-11 11:52:56
    概述:java的异常分为Error 和 Exception 。这两类都是接口Throwable 的子类。 异常分类方式: 1.运行时异常 和 非运行时异常 2.可查的异常(checked exceptions)和 不可查的异常(unchecked exceptions) 总结 ...
  • 1. @Transactional 注解属性信息 属性 描述 name 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器 propagation 事务传播行为,默认值为 REQUIRED isolation ...
  • Spring @Transactional的配置 xml配置文件中,添加事务管理器bean配置 <!-- 事务管理器配置,单数据源事务 --> <bean id="pkgouTransactionManager" class="org.springframework.jdbc.datasource....
  • 在我们开发中很多时候都要用到事务,例如转账、充值等等操作,这些我就不多BB了,于是很多人就选择最简单方式@Transactional注解,但是你真测试过事务异常时候会回滚吗?等生产环境遇到了在来查找原因那就晚...
  • 一、注解加载1.1 流程Spring是通过单例模式将@Transactional注解中内容加载进来,中间有一些是BeanFactory工作,我省去了,直接从注解相关类开始写流程了,流程大致如下图所示:image.png1.2 核心源码源码...
  • java事务回滚 @Transactional

    千次阅读 2018-12-24 11:17:41
    在方法中,使用 throw new Exception 或 try{}catch(){} 抛出或捕获异常,不会形成是事务回滚。 可以在事务回滚时候加上 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 可以回滚...
  • @Transactional 内部调用例子在 Spring ...若同一类中其他没有@Transactional 注解方法内部调用有@Transactional 注解方法,有@Transactional 注解方法事务被忽略,不会发生回滚@Servicepublic class A{...
  • 主要介绍@Transactional在底层是如何工作。之后文章将介绍:propagation(事务传播)和isolation(隔离性)等属性使用事务使用陷阱有哪些以及如何避免JPA和事务管理很重要一点是JPA本身并不提供任何类型声明...
  • 如果@transactional事务注解加在单测上,所测试数据不会对数据库有影响,不会污染数据库 @transactional事务注解加在单测上,只测试功能,测试完毕后会回滚数据 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,116
精华内容 446
关键字:

java的transactional

java 订阅