在前面的文章中,我们有了解到mysql数据库索引原理及mysql数据库事务及其事务的实现原理数据库锁。
在mysql的事务中,有四种事务隔离级别,分别解决了 脏读、不可重复读、幻读的问题。
在事务管理方面,除了事务隔离级别可以完善事务,还有哪些其它的方式可以来达到这种类似的效果呢?这个时候,我们可以看一下Spring为我们提供的解决方案。
我们在平时编写java代码时,只需要在响应的服务层上添加一个@Transactional注解即可,@Transactional注解中有配置响应的事务传播行为(Transaction Propagation Behavior)
那么,@Transactional注解,都为我们提供了哪些传播行为呢?我们一起来探索一下。
我们可以看一下@Transactional注解里面是怎么写的。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}其中,事务的传播行为为:Propagation,默认值为:Propagation.REQUIRED
Spring中一共提供了7种事务传播行为,分别如下:
/**
* Spring提供的7种事务传播行为
*/
public enum Propagation {
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
private final int value;
private Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}要理解事务的传播行为,我们首先需要理解一下事务是如何传播的,从哪来,到哪去。我们在学习事务的时候,都知道事务的原子性,也就是被添加的事务的方法为一个最小原子不可再分隔。
那么,事务的传播肯定是从方法A传递到方法B了。而Spring解决的只是方法之间的事务传播。
比如:
1、方法A有事务,方法B也有事务
2、方法A有事务,方法B没有事务
3、方法A没有事务,方法B有事务
4、方法A没有事务,方法B也没有事务
而Spring的7种事务传播,刚好四种对应了上面提到的四种,另外还有三种特殊的事务传播。
假设事务从方法A传播到方法B,用户需要面对方法B,此时,我们编写的方法A上有事务没有呢?
(1) 、如果此时方法A没有事务,那么就新建一个事务;如果有,就加入当前事务。这就是Propagation.REQUIRED,它是Spring默认的事务传播行为,适合绝大多数情况。
(2) 、如果没有,就新建一个任务;如果有,就将当前事务挂起。这就是Propagation.REQUIRES_NEW,意思就是新建一个事务,它和原来的事务没有任何关系了。
(3) 、如果没有,就新建一个任务;如果有,就在当前事务中嵌套其他事务。这就是Propagation.NESTED,也就是”嵌套事务”,所嵌套的子事务与主事务之间是有关联的(当主事务提交或回滚,子事务也会提交或回滚)
(4) 、如果没有,就以非事务方式执行;如果有,就在当前事务中嵌套其他事务。这就是Propagation.SUPPORTS,这种方式非常随意,没有就是没有,有就有,有点无所谓的态度。
(5) 、如果没有,就以非事务方式执行;如果有,就将当前事务挂起。这就是Propagation.NOT_SUPPORTED,这种方式非常强硬,没有就是没有,有也不支持,挂起来,不管它。
(6) 、如果没有,就以非事务方式执行;如果有,就抛出异常。这就是Propagation.NEVER,这种方式非常强硬,没有就是没有,有了反而报错。
(7) 、如果没有,就抛出异常;如果有,就使用事务。这就是Propagation.MANDATORY,这种方式是最强硬的,没有事务就直接报错。
怎么样,感觉是不是有种豁然开朗的感觉。
绝大多数情况下,我们使用Spring默认的事务传播行为即可满足所有的需求。
但是不用并不代表我们不去了解,毕竟这个是非常强大的。
2018年12月25日 20:13:48




