记录一下最近遇到的bug
//此时事务失效
class A{
methon A1{
A2()
}
@Transactional
methon A2{
A2()
}
}
原因:AOP使用的是动态代理的机制,它会给类生成一个代理类,事务的相关操作都在代理类上完成。内部方式使用this调用方式时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效。
解决方法
A:
class A{
@Transactional
methon A1{
A2()
}
@Transactional
methon A2{
A2()
}
}
这种方法等价于下面这种写法,A1调用A2则两者同属于一个事务中,如果A2抛出异常,则A1的操作也需要全部回滚
@Transactional
class A{
methon A1{
A2()
}
methon A2{
A2()
}
}
B:事务拆分,将A2抽出为class进行注入调用,这样A1调用A2时就会通过代理类调用方法。
class A{
A2 A2;
methon A1{
A2.A2()
}
}
@Transactional
class A2(){
methon A2{
A2()
}
}
顺带重温了一下Transactional的相关知识:
checked异常和unchecked异常checked异常:(编译异常)
表示无效,不是程序中可以预测的。比如无效的用户输入,文件不存在,网络或者数据库链接错误。这些都是外在的原因,都不是程序内部可以控制的。
必须在代码中显式地处理。比如try-catch块处理,或者给所在的方法加上throws说明,将异常抛到调用栈的上一层。
继承自java.lang.Exception(java.lang.RuntimeException除外)。
unchecked异常:(运行异常)
表示错误,程序的逻辑错误。是RuntimeException的子类,比如IllegalArgumentException, NullPointerException和IllegalStateException。
不需要在代码中显式地捕获unchecked异常做处理。
继承自java.lang.RuntimeException(而java.lang.RuntimeException继承自java.lang.Exception)。
@Transactional使用注意点
- @Transactional注解只能在抛出RuntimeException或者Error时才会触发事务的回滚,常见的非RuntimeException是不会触发事务的回滚的。但是我们平时做业务处理时,需要捕获异常,所以可以手动抛出RuntimeException异常或者添加rollbackFor
= Exception.class(也可以指定相应异常) - 只有public修饰的方法才会生效
- 方法内自调用导致的事务不生效
- @Transactional 注解属性 propagation 设置错误
- 异常被catch捕获导致@Transactional失效
- 数据库引擎不支持事务
```java
package org.springframework.transaction.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@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 {};
}
属性详解:
-
value:value这里主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1, txManager2。然后,用户可以根据这个参数来根据需要指定特定的txManager。那有同学会问什么情况下会存在多个事务管理器的情况呢? 比如在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的。
-
propagation: Propagation支持7种不同的传播机制
-
Isolation:四种隔离级别
参考网址: