当前位置:网站首页>controller层到底能不能用@Transactional注解?
controller层到底能不能用@Transactional注解?
2022-08-03 05:20:00 【likelong965】
⼀般情况下,@Transactional要放在service层,并且只需要放到最外层的方法上就可以了。
那么controller层到底能不能使用@Transactional注解呢?答案是可以使用的。(但是还是尽量在service层使用)其实在controller层使用 @Transactional 用法跟在service层使用是一样的。
①使用时代码尽量不要try…catch…
②如果真的要捕获异常,可以在catch语句中增加:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 语句,手动回滚,这样上层就无需去处理异常。
就拿下面这个controller层接口说起,这个新增用户接口,需要先新增基础信息,再新增详细信息,在两个新增操作之间模拟异常。
第一种:这种情况,发生异常代码直接捕获,异常根本不会向上抛,事务不会进行回滚,这也是正常操作。
@PostMapping("/addUser")
@Transactional
public String addUser(@RequestBody User user) {
try {
userMapper.insert(user);
//代码异常
int i = 1 / 0;
UserDetail userDetail = new UserDetail();
userDetail.setUserId(user.getId());
userDetail.setQq(String.valueOf(System.currentTimeMillis()).substring(0, 10));
userDetailMapper.insert(userDetail);
user.setUserDetail(userDetail);
} catch (Exception e){
log.error("insert false:" + e.getMessage());
return "fail";
}
return "success";
}
第二种:要是还想像第一种这种写法,还想做事务回滚,只能在catch语句中添加一行TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();进行手动回滚操作,如下:
@PostMapping("/addUser")
@Transactional
public String addUser(@RequestBody User user) {
try {
userMapper.insert(user);
//代码异常
int i = 1 / 0;
UserDetail userDetail = new UserDetail();
userDetail.setUserId(user.getId());
userDetail.setQq(String.valueOf(System.currentTimeMillis()).substring(0, 10));
userDetailMapper.insert(userDetail);
user.setUserDetail(userDetail);
} catch (Exception e){
log.error("insert false:" + e.getMessage());
// 手动回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return "fail";
}
return "success";
}
第三种:就是代码异常不管,可以正常事务回滚,如下:
@PostMapping("/addUser")
@Transactional
public String addUser(@RequestBody User user) {
userMapper.insert(user);
//代码异常
int i = 1 / 0;
UserDetail userDetail = new UserDetail();
userDetail.setUserId(user.getId());
userDetail.setQq(String.valueOf(System.currentTimeMillis()).substring(0, 10));
userDetailMapper.insert(userDetail);
user.setUserDetail(userDetail);
return "success";
}
原因:
默认spring事务只在发生未被捕获的 RuntimeException 时才回滚。
spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获 RuntimeException 的异常,但可以通过配置来捕获特定的异常并回滚,换句话说在service层的方法中不使用try catch 或者在catch中加上throw new RuntimeExcetpion(),这样程序异常时才能被aop捕获进而回滚。
边栏推荐
猜你喜欢
随机推荐
lintcode2330 · 计算x秒后的时间
icebreaker的垃圾话学习指南
MySQL 一些函数
1230: 蜂巢
web安全-sql注入漏洞
dataframe插入一列
【打印菱形】
D-PHY
【Arduino】关于“&”和“|” 运算-----多个参数运算结果异常的问题解决
Kaggle(四)Scikit-learn
【扫雷】多方法超详细 7.28
Makefile介绍
对角矩阵(diagonal matrix)
经典论文-ResNet
Makefile语法
【按位取反,逻辑操作符,条件操作符,逗号表达式,下标引用,函数调用,结构体】操作符后续+表达式求值(上)
Go (一) 基础部分3 -- 数组,切片(append,copy),map,指针
NotImplementedError: file structure not yet supported
-元素之和-
动态规划笔记