一、@Transaction

我们再编码过程中,大量使用到这个注解。一般情况下,@Transaction使用默认注解可以完成90%的功能,下面会针对一些特殊场景下,@Tansaction的使用注意

1.1 事务回滚

@Transactional()
public void rollback() throws SQLException {
    ... //do something
    throw new SQLException("exeception");
}

上述代码会回滚吗,答案是不会的。原因是:默认配置中,只会对RuntimeException(及其子类)才会进行回滚。因此,在一些抛出非运行时异常的场景下也希望回滚的,则需要进行配置

 
@Transactional(rollbackFor = Exception.class)

除了可以指定哪些异常回滚,也可以指定哪些异常不执行回滚,对应的是noRollbackFor

1.2 事务传播性

@Transaction中可以指定事务的传播性,可以在下面类中查询Spring 支持的事务传播类型,或者网上一搜也有很多

org.springframework.transaction.annotation.Propagation

这里举一个场景分析,在一个事务开启后,在下面场景中,select出来的依旧是事务开启时的数据快照,并无法获取其他事务对其的修改(不可重复读或幻读)

但我们的需求是想及时获取最新数据,那么可以利用事务的传播性,在当前事务中新开另外一个事务去读取

@Transactional(rollbackFor = Exception.class)
public void selectTransaction() {
    // do someThing but update dayEarn
    DayEarn dayEarn = self.selectNotSupported(17L);
    //....

}

@Transactional(propagation = Propagation.NOT_SUPPORTED, rollbackFor = Exception.class)
public DayEarn selectNotSupported(long autoId) {
    return dayEarnMapper.selectByPrimaryKey(autoId);
}
NOT_SUPPORTED传播性就是 如果当前存在事务,则挂起当前事务,新开一个事务去执行,完成会恢复挂起的事务

1.3 额外说明

我们知道,@Transaction注解的方法不能通过内部方法调用(当然不仅仅是这个注解),因此,可以通过Spring,把当前Bean实例注入到当前Bean一个属性中,即

@Service
public class MyService  {

    private MyService self;

    ...
}

有2种方式:

第一种方法,直接@Autowire

Spring对这种循环依赖是有解决办法的,前提是满足以下条件:

  1. Bean是单例,
  2. 通过属性注入的情况

因此,我们直接像注入其他类一样,注入自己的一个实例,如下

@Service
public class MyService  {

    @Autowired
    private MyService self;
}

第二种方法,通过BeanFactoryAware

虽然在第一种方法在大部分情况下是可行的,但是有些情况下还是会报循环依赖的问题(可以尝试在该类中即有@Transaction,又有@Async)

因此,建议使用BeanFactoryAware来注入,这样是在Bean初始完成后再set进来,而不是依赖Spring来解决循环依赖

 
@Service
public class MyService implements BeanFactoryAware {

    private MyService self;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        self = beanFactory.getBean(MyService.class);
    }
}

二、@Retry

Spring对重试机制的注解,需要加入@EnableRetry

典型使用方式

@Retryable(value = {RemoteAccessException.class}, maxAttempts = 2, backoff = @Backoff(delay = 500L))
public void retry() {
    System.out.println("rpc 调用失败");
    try {
        TimeUnit.MILLISECONDS.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    throw new RemoteAccessException("rpc 调用失败");
}
  • 注解中的value是一个Class数组,表示抛出哪些异常的时候回尝试重试
  • maxAttempts,最大执行次数,上面表示该方法2次执行失败,则不再进行重试
  • backoff,设定重试间隔,2次执行之间间隔500ms,(还可以设定多次间隔时间按照一定倍数递增)
如果需要在重试失败以后,再做一些其他的业务处理,可以使用@Recover注解来进行回调
@Recover
public void recover2(Exception e) {
    System.out.println("recover2" + e.getMessage());
}

注:如果存在多个@Recover类,那么只会匹配一个最接近,根据上面的例子,下面只有RemoteAccessException的才会执行

@Recover
public void recover1(RemoteAccessException e) {
    System.out.println("recover1" + e.getMessage());
}

@Recover
public void recover2(Exception e) {
    System.out.println("recover2" + e.getMessage());
}

三、@Async

前提:需要加入@EnableAsync

可以对一个方法进行异步调用,例如

@Async
public Future<Boolean> async() {
    //... do something
    return new AsyncResult<>(Boolean.TRUE); //or false
}

这样,在调用的时候,把当前方法放到一个线程池中,异步去执行。使用方法和Callable接口提交线程中完全一样。

如果需要指定一个特定的线程池,可以通过在@Async中指定线程池的beanName来确定。

@Async(value = "executor")
public Future<Boolean> async() {
    //... do something
    return new AsyncResult<>(Boolean.TRUE); //or false
}

四、组合使用

上述的功能实现基本都是基于AopProxy,因此,完全可以进行组合,例如 @Async和@Retry即可以完成异步重试,还是用上面的例子来进行组合

@Async(value = "executor")
public void asyncRetry() {
    self.retry();
}

@Retryable(value = {RemoteAccessException.class}, maxAttempts = 2, backoff = @Backoff(delay = 500L))
public void retry() {
    System.out.println("rpc 调用失败");

    throw new RemoteAccessException("rpc 调用失败");
}

@Recover
public void recover1(RemoteAccessException e) {
    System.out.println("recover1" + e.getMessage());
}

额外说明:如果一个类即包含了@Transaction注解,又包含了其他@Retry,@Async注解,那么Spring在生成动态代理的时候,并不通过对这个类进行多层动态代理,而是只代理一次,把这些额外功能做成多个切面

坦言spring中事务、重试、异步执行注解的更多相关文章

  1. spring对数据库的操作、spring中事务管理的介绍与操作

    jdbcTemplate的入门 创建maven工程 此处省略 导入依赖 <!-- https://mvnrepository.com/artifact/org.springframework/s ...

  2. 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制

    spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...

  3. Spring事务专题(四)Spring中事务的使用、抽象机制及模拟Spring事务实现

    Spring中事务的使用示例.属性及使用中可能出现的问题 前言 本专题大纲如下: 对于专题大纲我又做了调整哈,主要是希望专题的内容能够更丰富,更加详细,本来是想在源码分析的文章中附带讲一讲事务使用中的 ...

  4. Spring中事务的5种属性总结

    Sping的事务 和 数据库的事务是不同的概念,数据库的事务一般称为底层事务 Spring的事务是对这种事务的抽象 我称之为逻辑事务 Spring对事务的功能进行了扩展,除了基本的Isolation之 ...

  5. Spring中的@Valid 和 @Validated注解你用对了吗

    1.概述 本文我们将重点介绍Spring中 @Valid和@Validated注解的区别 . 验证用户输入是否正确是我们应用程序中的常见功能.Spring提供了@Valid和@Validated两个注 ...

  6. 【面试普通人VS高手系列】Spring中事务的传播行为有哪些?

    一个工作了2年的粉丝,私信了一个比较简单的问题. 说: "Spring中事务的传播行为有哪些?" 他说他能记得一些,但是在项目中基本上不需要配置,所以一下就忘记了. 结果导致面试被 ...

  7. 对于spring中事务@Transactional注解的理解

    现在spring的配置都喜欢用注解,这边就说下@Transactional 一.如何开启@Transactional支持 要使用@Transactional,spring的配置文件applicatio ...

  8. 阶段3 2.Spring_10.Spring中事务控制_3 作业-基于注解的AOP实现事务控制及问题分析_下

    此时没有异常 测试我们的方法 执行报错 注解在实际的测试过程中,实际的执行顺序是有问题的.会先调用最终通知.然后再调用后置通知 最终通知已经关闭了连接.再调用后置通知肯定报错. getThreadCo ...

  9. 阶段3 2.Spring_10.Spring中事务控制_8 spring基于纯注解的声明式事务控制

    新建项目 把之前项目src下的内容全部复制过来 pom.xml内复制过来 开始配置 新建一个config的包,然后再新建配置文件类SpringConfiguration @Configuration这 ...

随机推荐

  1. .Neter玩转Linux系列之六:Linux下MySQL的安装、配置、使用

    一.Linux安装MySQL (1)下载安装包:https://dev.mysql.com/downloads/mysql/ (2)解压并安装 命令:tar zxvf 文件名 解压完成之后,重名一下文 ...

  2. 5分钟教你玩转 sklearn 机器学习(上)

    假期结束,你的状态有没有回归?那么,放空脑袋后,先来学习学习,欢迎大家继续关注腾讯云技术社区. 作者:赵成龙 这是一篇很难写的文章,因为我希望这篇文章能对大家有所帮助.我不会给大家介绍机器学习,数据挖 ...

  3. Ubuntu 普通用户提升到root权限

    方法一.修改passwd文件 1.编辑passwd文件 sudo vim /etc/passwd 2.找到你想提权的用户(比如test),将用户名后面的数字改成0 找到用户test test:x::: ...

  4. Shell一个文件并等待完成

    Option Explicit Private Declare Function OpenProcess Lib "kernel32" _ (ByVal dwDesiredAcce ...

  5. 深入理解计算机系统(4.1)------Y86指令集体系结构

    本章我们将进入处理器体系结构介绍的神秘海洋中,我们熟悉的手机,电脑等设备的核心硬件都离不开处理器.处理器可以称的上是人类创造的最复杂的系统之一,一块手指大小的硅片,可以容纳一个完整的高性能处理器.大的 ...

  6. 简单说下C#变量的作用域

    变量的作用域分为局部变量和全局变量举个小例子 class Program { int i = 3;//这个变量i 需要实例化Program才能使用 static void Main(string[] ...

  7. 吾八哥学Python(三):了解Python基础语法(上)

    学习一门开发语言首先当然是要熟悉它的语法了,Python的语法还算是比较简单的,这里从基础的开始了解一下. 标识符1.第一个字符必须是字母表中字母或下划线'_'.2.标识符的其他的部分有字母.数字和下 ...

  8. 张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231

    GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/DS3231 注意:不包含闹钟设置

  9. 浅谈javascript继承体系

    最近做web项目,接触了jquery等框架,虽然使用方便,但是还是想学习下Javascript,今天分享下最近对js原型继承的理解,不足之处欢迎指正. 一.构造器的原型属性与原型对象 刚接触js时通常 ...

  10. IDEA启动后页面没有tomcat server选项,显示灰色问号和红叉不能使用

    说明:自己好几次硬盘莫名其妙读不出来导致电脑重启后idea没有了tomcat选项,原来的tomcat上显示灰色的问号和红色小叉子,网上搜了好久加上自己摸索,终于解决了.现在记一下也分享一下,省的下回又 ...