正文
关于 @Transactional 异常的问题,首先要保证数据源及前置事务配置正确且生效,这是前提,就不在当前结果讨论的范围 (不含多数据源的场景)。
其次spring的@Transactional是通过注解切面实现,这要保证 为spring容器所管理的实例对象且符合切面能正常执行的条件。(方法修饰符应是public)
如果当前类是spring的实例类,当前类的方法中直接 this.xxx()
进行调用带注解的切面方法,切面功能不会生效。另外 @Transactional 中 propagation 属性可以来指定事务传播行为,一般不指定,使用的是REQUIRED(默认)类型:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
另外在执行事务的业务逻辑中不能包含耗时计算(如rpc调用、http调用等)
基于业务基本场景一般就涉及带返回值和不带返回值的两种,加上尽量避免 @Transactional 使用的地方过多,可统一放在一处进行维护(避免每次都要特别验证配置是否生效)
以下是博主多年工作推荐的一种实现方式(有需要其他方法或调整自行处理即可,欢迎大家留言交流~):
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.function.Supplier;
/**
* @author 新程快咖员
*/
@Service
public class TransactionalTaskHelper {
private static TransactionalTaskHelper INSTANCE;
/**
* 设置实例对象 -- 通过runner、InitializingBean等方式初始化
*
* @param instance
*/
static void setInstance(TransactionalTaskHelper instance) {
INSTANCE = instance;
}
/**
* 获取实例对象
*
* @return
*/
public static TransactionalTaskHelper getInstance() {
return INSTANCE;
}
/**
* 不带返回值的业务逻辑执行
* <p>代码示例:<p>
* <code>TransactionalTaskHelper.getInstance().execute(() -> {
* //要执行的业务代码
* });</code>
*
* @param runnable
*/
@Transactional(rollbackFor = Exception.class)
public void execute(Runnable runnable) {
runnable.run();
}
/**
* 带返回值的业务逻辑执行
* <p>代码示例:<p>
* <code>TransactionalTaskHelper.getInstance().execute(() -> {
* //要执行的业务代码 (这里可以返回任意类型的结果)
* return 1;
* });</code>
*
* @param supplier
* @return 结果
*/
@Transactional(rollbackFor = Exception.class)
public <T> T execute(Supplier<T> supplier) {
return supplier.get();
}
@Component
public static class TransactionalTaskHelperInitializingBean implements InitializingBean {
@Autowired
private ApplicationContext applicationContext;
@Override
public void afterPropertiesSet() throws Exception {
setInstance(applicationContext.getBean(TransactionalTaskHelper.class));
}
}
}
调用方式:
//不带返回值的业务逻辑执行
TransactionalTaskHelper.getInstance().execute(() -> {
//要执行的业务代码
});
//带返回值的业务逻辑执行
Integer size = TransactionalTaskHelper.getInstance().execute(() -> {
//要执行的业务代码 (这里可以返回任意类型的结果)
return 1;
});
验证事务是否回滚示例: (抛出异常后可见保存的业务1数据被回滚)
TransactionalTaskHelper.getInstance().execute(() -> {
//要执行的业务代码
//保存业务1数据 todo
if (true) {
throw new RuntimeException("主动抛出RuntimeException异常测试回滚");
}
//保存业务2数据 todo
});
插件分享
这还是我认识的idea插件吗?搜索maven依赖版本绝了,升级maven版本功能也超级好使~