简介
Spring使用AOP代理实现事务,默认情况下只捕获 RuntimeException 的异常
概况
- 抛出非RuntimeException
- 若异常被捕获且不抛出,则不会回滚
- 不经Spring代理,直接调用本类方法
- 未正确使用事物的propagation(传播)属性
- 方法被static、final或非public方法修饰
- 业务类没有托管给Spring注册为Bean对象
- 切面的优先级在事物之前,需手动回滚异常
- 数据库使用了不支持事务的存储引擎,如:Mysql中的MyISAM
- 在多线程场景中,获取到的数据库连接是不一样的,即是不属于同一事务,则无法回滚
- 需要调用的业务类,在事物被声明之前注册成Bean对象,即优先级高于事物,导致事物失效
案列一
问题详情
一、抛出非RuntimeException
public void saveUser(User user) {
try {
userDao.save(user);
} catch (Exception e) {
//抛出非RuntimeException
throw new IllegalAccessException();
}
}
解决方案
一、申明回滚异常
//通过注解rollbackFor,申明回滚的异常
@Transactional(rollbackFor = Exception.class)
public void saveUser(User user) {
try {
userDao.save(user);
} catch (Exception e) {
throw new IllegalAccessException();
}
}
案列二
问题详情
一、若异常被捕获且不抛出,则不会回滚
public void saveUser(User user) {
try {
userDao.save(user);
} catch (Exception e) {
logger.info("保存失败:错误信息为:" + e);
}
}
解决方案
一、显式抛出异常
public void saveUser(User user) {
try {
userDao.save(user);
} catch (Exception e) {
logger.info("保存失败:错误信息为:" + e);
//显式抛出异常
throw new RuntimeException();
}
}
二、手动回滚事物
public void saveUser(User user) {
try {
userDao.save(user);
} catch (Exception e) {
logger.info("保存失败:错误信息为:" + e);
//手动回滚事物
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
案列三
问题详情
一、不经Spring代理,直接调用本类方法
@Service
public class UserServiceImpl implements UserService {
public boolean saveUser(User user) {
//不经Spring代理,直接调用本类方法
return this.save(user);
}
@Transactional(rollbackFor = Exception.class)
public boolean save(User user) {
return userDao.save(user);
}
}
解决方案
一、使用AspectJ 代理
1. 在启动类上开启代理
@SpringBootApplication
//启用AspectJ 代理
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
2. 使用代理调用本地方法
@Service
public class UserServiceImpl implements UserService {
public boolean saveUser(User user) {
//使用AspectJ 代理
return ((UserService) (AopContext.currentProxy())).save(user);
}
@Transactional(rollbackFor = Exception.class)
public boolean save(User user) {
return userDao.save(user);
}
}
案列四
问题详情
一、未正确使用事物的propagation(传播)属性
@Transactional(propagation = Propagation.NOT_SUPPORTED)
解决方案
一、使用默认propagation(传播)属性
@Transactional(propagation = Propagation.REQUIRED)
案列八
JPA配置InnoDB存储引擎
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
网友评论