坦言spring中事务、重试、异步执行注解

一、@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在生成动态代理的时候,并不通过对这个类进行多层动态代理,而是只代理一次,把这些额外功能做成多个切面

时间: 2024-10-30 21:27:22

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

Spring中事务管理

1.什么是事务? 事务是逻辑上的一组操作,这组操作要么全部成功,要么全部失败 2.事务具有四大特性ACID 1)原子性(Atomicity):即不可分割性,事务要么全部被执行,要么就全部不被执行.如果事务的所有子事务全部提交成功,则所有的数据库操作被提交,数据库状态发生转换:如果有子事务失败,则其他子事务的数据库操作被回滚,即数据库回到事务执行前的状态,不会发生状态转换. 2)一致性(Consistency):事务的执行使得数据库从一种正确状态转换成另一种正确状态.例如对于银行转账事务,不管事务

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

新建项目 把之前项目src下的内容全部复制过来 pom.xml内复制过来 开始配置 新建一个config的包,然后再新建配置文件类SpringConfiguration @Configuration这个注解是可写可不写的. 这个类会做为字节码的参数传给ApplicationContext @ComponentScan配置要扫描的包 @Import 但是这个Import要导谁呢? 新建JdbcConfig类 这一就可以通过Import导入JdbcConfig这个类 xml里面扫描包的配置可以省略掉

【转】Spring中事务与aop的先后顺序问题

[原文链接] http://my.oschina.net/HuifengWang/blog/304188 [正文] Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟spring的事务aop执行的先后顺序问题,比如说动态切换数据源的问题,如果事务在前,数据源切换在后,会导致数据源切换失效,所以就用到了Order(排序)这个关键字. 步骤01:    我们可以通过在@AspectJ的方法中实现org.springframework.core.Ordered 这个接口来

spring的事务,详解注解@Transactional

事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持. Spring 事务管理分为编程式和声明式的两种方式. 编程式事务指的是通过编码方式实现事务,编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager. 声明式事务管理建立在AOP之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务. 显然声明式事务管理要优于编程式

Spring中事务传播行为

1. Spring中七种事务传播行为 PROPAGATION(蔓延.传播.传输) 事务传播行为类型 说明 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中.这是默认的事务传播行为 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行. PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常. PROPAGATION_REQUIRES_NEW 新建事务,如果

spring中事务配置

1:事务实现方式是通过动态代理实现:通过xml配置方式: 1:其中,<tx:method name="trans" />中的name属性,支持通配符,比如*   name="trans*"代表所有以trans开头的方法,都适用 一个通用的事务配置: 2:使用注解方式配置事务: 添加DI注解解析器,IOC注解解析器,事务注解解析器(TX注解解析器<tx:annotation-diven transaction-manager="txMana

阶段3 2.Spring_10.Spring中事务控制_4 spring中事务控制的一组API

分析aop的 xml 的代码.更直观一些 事务提交和回滚就是我们重复的代码 spring业余事务管理器,我们拿过来直接用就可以 提交和回滚的后面直接调用释放.所以释放资源之类就是多余的 在绑定连接到线程的时候,直接就设置成false,所以开启事务这个通知 也是多余的 spring中的事务 需要先导入包pom.xml 用刚上线类.DataSourceTransactionManager 如果用到Hibernate的话.这个是真正带着代码的实现类 TransactionDefinition 事务的隔

Spring中常用的配置和注解详解

一.  Spring中常用的配置文件详解 Spring中的配置文件详解 1.<!-- 配置注解bean的扫描路径 该配置表示从cn包下开始扫描--> <context:component-scan base-package="cn"></context:component-scan> 2.<!-- 加载资源文件 其中Location表示从哪个路径加载配置文件properties--> <context:property-placeh

spring中事务的回滚

https://www.cnblogs.com/zeng1994/p/8257763.html(浅谈Spring中的事务回滚) http://www.cnblogs.com/nnngu/p/8627662.html (Spring的编程式事务和声明式事务) 原文地址:https://www.cnblogs.com/lqtbk/p/10729469.html