1.Transactional的实现流程
- 当方法被访问时,请求会通过AOP被TransactionInterceptor拦截并调用invokeWithinTransaction
- invokeWithinTransaction中用于获得目标方法的事务属性,属性包含如何管理事务的相关配置
TransactionAttributeSource tas = this.getTransactionAttributeSource();
TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
- 确定用于管理当前事务的事务管理器,下文针对于平台事务
TransactionManager tm = this.determineTransactionManager(txAttr);
事务管理器分为反应式事务管理器(ReactiveTransactionManager)和平台事务管理器(PlatformTransactionManager),前者需要继承AbstractReactiveTransactionManager或实现ReactiveTransactionManager,是为了实现响应式编程设计的,而后者支持持久化存储方案,内置有:DataSourceTransactionManager用于JDBC事务管理、JpaTransactionManager用于JPA、JtaTransactionManager用于JTA
- 若需要,则创建事务
TransactionInfo txInfo = this.createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm) {
status = tm.getTransaction((TransactionDefinition)txAttr);
}
5.最后执行原方法
retVal = invocation.proceedWithInvocation();
2.Transactional作用的方法无法被重写
当方法的访问修饰符不是public,或方法被final修饰时,@Transactional会失效
@Transactional
private Result<List<Patient>> getPatients() {
return Result.success(patientMapper.selectList(null));
}
@Transactional
public final Result<List<Patient>> getPatients() {
return Result.success(patientMapper.selectList(null));
}
因为Transactional是通过AOP实现对目标方法的增强,需要通过jdk动态代理或Cglib生成代理类,若该方法被private或final修饰,则无法重写该方法,导致无法创建代理类。
public abstract class TransactionAspectSupport {
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
TransactionAttributeSource tas = this.getTransactionAttributeSource();
TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
}
}
通过getTransactionAttribute()获得目标方法的事务属性
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource{
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
}
}
当修饰符不是public的时候,就返回空的事务属性,因此不会提供事务
3. 类方法的直接调用
@Override
public Result<List<Patient>> getPatients() {
Patient patient1 = getPatientById(1).getData();
Patient patient2 = getPatientById(2).getData();
return Result.success(List.of(patient1, patient2));
}
@Override
@Transactional
public Result<Patient> getPatientById(Integer id) {
Patient patient = patientMapper.selectOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getId, id));
return Result.success(patient);
}
getPatientById()方法实际上为this.getPatientById(),由于事务是通过获得代理对象来实现的,直接调用对象内的方法,不会生成代理对象,导致无法实现事务的功能
解决方法
-
新建一个Service方法,将需要交给事务管理的方法放进去
-
注入自己,在调用方法时,通过注入的对象中的方法
@Autowired
private PatientService patientService;
@Override
public Result<List<Patient>> getPatients() {
Patient patient1 = patientService.getPatientById(1).getData();
Patient patient2 = patientService.getPatientById(2).getData();
return Result.success(List.of(patient1, patient2));
}
@Override
@Transactional
public Result<Patient> getPatientById(Integer id) {
Patient patient = patientMapper.selectOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getId, id));
return Result.success(patient);
}
3.使用AopContext.currentProxy()获取当前对象的代理对象,调用代理对象内的方法
@Override
public Result<List<Patient>> getPatients() {
PatientService proxy = (PatientService) AopContext.currentProxy();
Patient patient1 = proxy.getPatientById(1).getData();
Patient patient2 = proxy.getPatientById(2).getData();
return Result.success(List.of(patient1, patient2));
}
@Override
@Transactional
public Result<Patient> getPatientById(Integer id) {
Patient patient = patientMapper.selectOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getId, id));
return Result.success(patient);
}