引用自:https://blog.csdn.net/fanxb92/article/details/81296005

先简单介绍一下Spring事务的传播行为:

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

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。
然后说一下Spring事务的回滚机制:

Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。Spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtimeException)。

如果你在方法中有try{}catch(Exception e){}处理,那么try里面的代码块就脱离了事务的管理,若要事务生效需要在catch中throw new RuntimeException ("xxxxxx");

再简单介绍一下@Transactional注解底层实现方式吧,毫无疑问,是通过动态代理,那么动态代理又分为JDK自身和CGLIB,这个也不多赘述了,毕竟今天的主题是如何将@Transactional对于事物的控制应用到炉火纯青。哈哈~

第一点要注意的就是在@Transactional注解的方法中,再调用本类中的其他方法method2时,那么method2方法上的@Transactional注解是不!会!生!效!的!但是加上也并不会报错,拿图片简单帮助理解一下吧

@Transactional注解通过AOP实现方式图解1
通过代理对象在目标对象前后进行方法增强,也就是事务的开启提交和回滚。那么继续调用本类中其他方法是怎样呢,如下图

@Transactional注解通过AOP实现方式图解2
可见目标对象内部的自我调用,也就是通过this.指向的目标对象将不会执行方法的增强。

先说第二点需要注意的地方,等下说如何解决上面第一点的问题。第二点就是@Transactional注解的方法必须是公共方法,就是必须是public修饰符!!!

至于这个的原因,发表下个人的理解吧,因为JVM的动态代理是基于接口实现的,通过代理类将目标方法进行增强,想一下也是啦,没有权限访问那么你让我怎么进行,,,好吧,这个我也没有深入研究底层,个人理解个人理解。

在这里我也放个问题吧,希望有高手可以回复指点指点我,因为JVM动态代理是基于接口实现的,那么是不是service层都要按照接口和实现类的开发模式,注解才会生效呢,就是说controller层直接调用没有接口的service层,加了注解也一样不起作用吧,这个懒了,没有测试,其一是因为没有人会这么开发吧,其二是我就认为是不起作用的,哈哈,,,

下面来解决一下第一点的问题,如何在方法中调用本类中其他方法呢。

通过AopContext.currentProxy ()获取到本类的代理对象,再去调用就好啦。因为这个是CGLIB实现,所以要开启AOP,当然也很简单,在springboot启动类上加上注解@EnableAspectJAutoProxy(exposeProxy = true)就可以啦,这个依赖大家自行搜一下就好啦。要注意,注意,代理对象调用的方法也要是public修饰符,否则方法中获取不到注入的bean,会报空指针错误。

emmmm,我先把调用的方式和结果说下吧。自己简单写了代码,有点粗糙,就不要介意啦,嘿嘿。。。

Controller中调用Service

@RestController
public class TransactionalController {
 
    @Autowired
    private TransactionalService transactionalService;
 
    @PostMapping("transactionalTest")
    public void transacionalTest(){
        transactionalService.transactionalMethod();
    }
}
Service中实现对事务的控制:接口

public interface TransactionalService {
    void transactionalMethod();
}
Service中实现对事务的控制:实现类        (各种情况的说明都写在图片里了,这样方便阅读,有助于快速理解吧)

上面两种情况不管使不使用代理调用方法1和方法2,方法transactionalMethod都处在一个事务中,四条更新操作全部失败。

那么有人可能会有疑问了,在方法1和方法2上都加@Transactional注解呢?答案是结果和上面是一致的。

小结只要方法transactionalMethod上有注解,并且方法1和方法2都处于当前事务中(不使用代理调用,方法1和方法2上的@Transactional注解是不生效的;使用代理,需要方法1和方法2都处在transactionalMethod方法的事务中,默认或者嵌套事务均可,当然也可以不加@Transactional注解),那么整体保持事务一致性。

如果想要方法1和方法2均单独保持事务一致性怎么办呢,刚说过了,如果不是用代理调用@Transactional注解是不生效的,所以一定要使用代理调用实现,然后让方法1和方法2分别单独开启新的事务,便OK啦。下面摆上图片。

这两种情况都是方法1和方法2均处在单独的事务中,各自保持事务的一致性。

接下来进行进一步的优化,可以在transactionalMethod方法中分别对方法1和方法2进行控制。要将代码的艺术发挥到极致嘛,下面装逼开始。

代码太长了,超过屏幕了,粘贴出来截的图,红框注释需要仔细看,希望不要影响你的阅读体验,至此,本篇关于@Transactioinal注解的使用就到此为止啦,

简单总结一下吧:

1、就是@Transactional注解保证的是每个方法处在一个事务,如果有try一定在catch中抛出运行时异常。

2、方法必须是public修饰符。否则注解不会生效,但是加了注解也没啥毛病,不会报错,只是没卵用而已。

3、this.本方法的调用,被调用方法上注解是不生效的,因为无法再次进行切面增强。

Spring对于事务的控制@Transactional注解详解的更多相关文章

  1. spring的事务解决方案之@Transactional注解

    首先此注解位于 org.springframework.transaction.annotation 这个包路径下面, 事务有两种类别,一种是编程式事务,另一种是声明式事务,显然此注解是声明式事务,这 ...

  2. @Transactional注解详解

    默认遇到throw new RuntimeException("...");会回滚   需要捕获的throw new Exception("...");不会回滚 ...

  3. SpringBoot事务注解详解

    @Transactional spring 事务注解 1.简单开启事务管理 @EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的 <tx:ann ...

  4. 26.SpringBoot事务注解详解

    转自:https://www.cnblogs.com/kesimin/p/9546225.html @Transactional spring 事务注解 1.简单开启事务管理 @EnableTrans ...

  5. Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

  6. Spring IoC 公共注解详解

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 什么是公共注解?公共注解就是常见的Java ...

  7. 转载 Spring、Spring MVC、MyBatis整合文件配置详解

    Spring.Spring MVC.MyBatis整合文件配置详解   使用SSM框架做了几个小项目了,感觉还不错是时候总结一下了.先总结一下SSM整合的文件配置.其实具体的用法最好还是看官方文档. ...

  8. coding++:SpringBoot-事务注解详解

    @Transactional spring 事务注解 1.简单开启事务管理 @EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的 <tx:ann ...

  9. spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean ...

随机推荐

  1. Oracle 03113

    SYSTEM的只有2M可以用了,还是需要 扩增 SYSTEM和SYSAUX的表空间 SELECT a.tablespace_name,a.bytes/1024/1024 total_M,b.bytes ...

  2. mac 下面用dd 制作u盘启动

    用dd来把安装包烧到U盘的,发现U盘变小了,mac磁盘工具也不能格式化,就只好用命令行了.diskutil list #1.找到U盘的代号 比如disk1diskutil unmountDisk /d ...

  3. Comparable接口的使用

    功能: Comparable接口可用于对象的排序或者对象的分组 介绍: Comparable接口强行对实现它的类的每个实例进行自然排序,该接口的唯一方法compareTo方法被称为自然比较方法 方法: ...

  4. kotlin基础 函数编写规则

  5. Ant Design Pro Vue 时间段查询 问题

    <a-form-item label="起止日期" :labelCol="{lg: {span: 7}, sm: {span: 7}}" :wrapper ...

  6. Jenkins build 后 tomcat 启不来

    Jenkins build 后 war 包复制到 tomcat 下,启不来 添加 :export BUILD_ID=dontKillMe /usr/local/iron/tomcat8085/bin/ ...

  7. MySQL数据类型:UNSIGNED注意事项(转)

    原文地址:https://www.cnblogs.com/blankqdb/archive/2012/11/03/blank_qdb.html 1. UNSIGNED UNSIGNED属性就是将数字类 ...

  8. gitlib配置push后自动触发jenkins构建sonar扫描

    jenkins所用到的插件: Gitlab Hook Plugin 配置步骤 1.先进入gitlab的个人设置,生成api token 2.复制生成的访问令牌,打开jenkins的凭据,添加选择类型是 ...

  9. Mysql日期函数说明

    1.获取当天日期 current_date  ->   2019-07-17 00:00:00 2.获取昨天日期函数 date_sub(current_date,INTERVAL 1 day)  ...

  10. [Go] 数据类型,变量与变量作用域,常量

    // var.gopackage main import ( "fmt" ) func main() { // 声明变量的一般形式是使用 var 关键字,可以一次声明多个变量 // ...