@Transactional实现原理
Transactional是spring中定义的事务注解,在方法或类上加该注解开启事务。主要是通过反射获取当前对象的注解信息,利用AOP(代理模式)对编程式事务进行封装实现
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
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.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
String[] label() default {};
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
String timeoutString() default "";
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
手动实现事务自定义注解
自定义注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
//自定义注解的属性
int id() default 0;
String name() default "默认名称";
String[] arrays() default {};
String title() default "默认标题";
}
封装编程式事务
@Component
@Scope("prototype")
public class TransactionUtil {
// 全局接受事务状态
private TransactionStatus transactionStatus;
// 获取事务源
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
// 开启事务
public TransactionStatus begin() {
System.out.println("开启事务");
transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
return transactionStatus;
}
// 提交事务
public void commit(TransactionStatus transaction) {
System.out.println("提交事务");
if (dataSourceTransactionManager != null) {
dataSourceTransactionManager.commit(transaction);
}
}
public void rollback(TransactionStatus transaction) {
System.out.println("回滚事务");
if (dataSourceTransactionManager != null) {
dataSourceTransactionManager.rollback(transaction);
}
}
}
AOP触发事务
@Component
@Aspect
public class AopTransaction {
@Autowired
private TransactionUtil transactionUtil;
private TransactionStatus transactionStatus;
/**
* 环绕通知,在方法 前---后 处理事情
*
* @param pjp 切入点
*/
@Around("execution(* com.sl.service.*.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
// 获取方法的注解
MyAnnotation annotation = this.getMethodMyAnnotation(pjp);
// 判断是否需要开启事务
transactionStatus = begin(annotation);
// 调用目标代理对象方法
pjp.proceed();
// 判断关闭事务
commit(transactionStatus);
}
/**
* 获取代理方法上的事务注解
*
* @param pjp
* @return
* @throws Exception
*/
private MyAnnotation getMethodMyAnnotation(ProceedingJoinPoint pjp) throws Exception {
// 获取代理对象的方法
String methodName = pjp.getSignature().getName();
// 获取目标对象
Class<?> classTarget = pjp.getTarget().getClass();
// 获取目标对象类型
Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
// 获取目标对象方法
Method objMethod = classTarget.getMethod(methodName, par);
// 获取该方法上的事务注解
MyAnnotation annotation = objMethod.getDeclaredAnnotation(MyAnnotation.class);
return annotation;
}
/**
* 开启事务
*
* @param annotation
* @return
*/
private TransactionStatus begin(MyAnnotation annotation) {
if (annotation == null) {
return null;
}
return transactionUtil.begin();
}
/**
* 提交事务
*
* @param transactionStatus
*/
private void commit(TransactionStatus transactionStatus) {
if (transactionStatus != null) {
transactionUtil.commit(transactionStatus);
}
}
/**
* 异常通知进行 回滚事务
*/
@AfterThrowing("execution(* com.sl.service.*.*(..))")
public void afterThrowing() {
// 获取当前事务 直接回滚
if (transactionStatus != null) {
transactionUtil.rollback(transactionStatus);
}
}
}
失效第一种
Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用
@Service
public class TestServiceImpl {
@Autowired
TestMapper testMapper;
@Transactional
void insert(SysUserOrgPo sysUserOrgPo) {
int re = testMapper.insert(sysUserOrgPo);
if (re > 0) {
throw new BaseException("发生异常")
}
testMapper.insert(new SysUserOrgPo("张三","1234"));
}
}
此时调用此方法, @Transactional会失效,testMapper.insert(sysUserOrgPo)不会回滚,根本原因是@Transactional的实现通过的AOP实现,也就是动态代理实现,如果方法上的修饰符都是非public的时候,那么将不会创建代理对象,所以事务也就不生效,方法上使用final、static修饰也不会创建代理对象
失效第二种
在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启
@Service
public class TestServiceImpl {
@Autowired
TestMapper testMapper;
@Transactional
public void insert(SysUserOrgPo sysUserOrgPo) {
int re = testMapper.insert(sysUserOrgPo);
if (re > 0) {
throw new BaseException("发生异常")
}
testMapper.insert(new SysUserOrgPo("张三","1234"));
}
public void testInnerInvoke(){
//内部调用事务方法,@Transactional失效
testServiceImpl.insertTestInnerInvoke();
}
}
如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过了代理对象,肯定就是没有代理逻辑了
失效第三种
事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚,原因是实现逻辑是只有捕获到异常才会回滚事务,列举源码如下
try {
retVal = invocation.proceedWithInvocation();
} catch (Throwable var20) {
// 事务回滚
this.completeTransactionAfterThrowing(txInfo, var20);
throw var20;
} finally {
this.cleanupTransactionInfo(txInfo);
}
失效的其他情况
- 多线程调用事务是会失效的,事务是建立在同一个数据链接上,多线程可能拿到的连接不是同一个连接,所以事务是会失效的
- 方法的事务传播类型不支持事务,如,REQUIRES_NEW调用NOT_SUPPORTED
- 数据库不支持事务,如MyISAM
- 方法上使用final、static修饰,就是不能jdk动态代理
- 事务方法未被spring管理,就是类上没加@service