版权声明:@412958751 https://blog.csdn.net/Jake_JJJ/article/details/81568728
@事务失效之谜
为什么会产生事务失效呢?
众所周知事务是源于代理模式而进行横向切入的(AOP)如下列代码:
package com.nyhs.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import com.nyhs.transaction.TransactionUtils;
@Component
@Aspect
public class UserAop {
//注入事务工具类
@Autowired
TransactionUtils transactionUtils;
//设置连接点
@Pointcut("execution(* com.nyhs.service.impl.UserDaoImpl.add(**))")
public void point() {
}
//异常通知
@AfterThrowing("point()")
public void afterThrowing() {
System.out.println("回滚事务");
// 获取事务切面,获取当前事务状态,进行回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
//环绕通知
@Around("point()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
TransactionStatus transactionStatus = transactionUtils.begin();
// 执行代理方法
proceedingJoinPoint.proceed();
transactionUtils.commit(transactionStatus);
System.out.println("提交事务成功");
}
}
在这里我使用的是Spring的Aop切面方法进行切入代理,在这里我们所切入的方法为com.nyhs.service.impl这个包中的UserDaoImpl中的add方法
@Pointcut("execution(* com.nyhs.service.impl.UserDaoImpl.add(**))")
public void point() {
}
这时我们来看一下TransactionUtils这个工具类。
package com.nyhs.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
@Component
public class TransactionUtils {
//获取事务管理器
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
/**
* 开始事务返回一个当前事务对象
*
* @return
*/
public TransactionStatus begin() {
//获取当前事务,设置传播级别为默认的传播级别
return dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
}
/**
* 获取当前事务状态<br>
* 提交事务
*
* @param transactionStatus 获取当前事务状态
*/
public void commit(TransactionStatus transactionStatus) {
dataSourceTransactionManager.commit(transactionStatus);
}
/**
* 获取当前事务状态<br>
* 回滚事务
*
* @param transactionStatus 获取当前事务状态
*/
public void rollback(TransactionStatus transactionStatus) {
dataSourceTransactionManager.rollback(transactionStatus);
}
}
事务切入方法:
package com.nyhs.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.nyhs.dao.UserDao;
import com.nyhs.entity.User;
import com.nyhs.service.UserService;
@Component
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
//添加数据
public void add(User user) throws Exception {
userDao.add(user.getClass());
}
}
这段代码的add方法便是我们所要进行事务管理的方法。
好,当这些我们都准备好了,我们来讲解事务失效之谜。
何为事务失效?
事务失效是指当某个方法添加了事务管理,但是当方法出现异常时却不会进行事务管理。
其中有以下原因:
1、在所切入方法进行try、catch,首先我们得讲解事务如何判断是否进行回滚,事务进行是否回滚的根本原因为异常,什么意思呢?
意思是当事务所切入的方法没有抛出异常而导致的无法rollback(回滚)这才会导致事务失效。
例:(我将上面的add方法进行改造)
package com.nyhs.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.nyhs.dao.UserDao;
import com.nyhs.entity.User;
import com.nyhs.service.UserService;
@Component
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
public void add(User user){
try {
userDao.add(user.getClass());
} catch (Exception e) {
//这里我不进行抛出异常
System.out.println("异常中...");
}
}
}
这样便会导致当前异常未被事务所捕捉。如果想要在所切入的方法中try、catch的话可以使用
catch (Exception e) {
//获取当前线程中的事务,进行回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
这样在catch方法中就可以进行回滚事务
2、Spring事务失效
为什么会导致Spring事务失效?其根本原因为Spring事务所捕捉的异常为RuntimeException,所以才会导致异常无法被捕捉到,无法进行回滚
可以手动设置切入方法的事务异常捕捉所捕捉的异常
长时间的异常失效可能会导致数据库中的表进行死锁,以及事务被挂起导致的长时间占用堆内存(内存泄漏)也就是无法被JVM GC,这种现象也可以称作长期可达。
谢谢大家观看,如有不对,或者觉得博主抄袭可联系博主QQ412958751。