Spring @Transactional 抛出异常,会在什么时候回滚?

wwang221 2017-06-14 10:44:32
今天尝试事务回滚的时候遇到一个问题:
我在controller中try一个方法,该方法执行一条插入语句,带有@Transactional注解,并会抛出一个异常。controller中catch这个异常之后,从控制台输出插入的内容
我感觉应该是插入语句回滚,内容被删除,然而结果是:数据库确实回滚了,也确实输出了被插入的内容。
想问问大神,这是什么原理?
controller:
@RequestMapping("/regist")
public ModelAndView regist(HttpServletRequest request, User user) throws Exception {
if (checkParams(new String[] { user.getUsername(), user.getPassword() })) {
//TODO @Transaction check if the account has already exist
try {
userService.saveUser(user);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("regist"+e.getMessage());
request.setAttribute("describe", e.getMessage());
}
request.setAttribute("username", user.getUsername());
request.setAttribute("password", user.getPassword());
System.out.println(user);
return new ModelAndView("succ");
}
return new ModelAndView("regist");
}

service:
@Transactional(rollbackFor = Exception.class)
public void saveUser(User user) throws Exception {
if (user != null && user.getId() != null) {
userDao.updateUser(user);
} else {
// TODO find if there is a repetition, can also use SQL
try {
List<User> allUser = userDao.getUser();
userDao.insertUser(user);
for (User _user : allUser) {
if (_user.getUsername().equals(user.getUsername()))
throw new Exception("The account is exist!");
}
} catch (Exception e) {
throw e;
}
}
}

控制台输出结果:
User [userid=1, username=1, password=1]
registThe account is exist!
User [userid=2, username=1, password=2]
数据库:
...全文
4241 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_40771549 2021-06-21
  • 打赏
  • 举报
回复

代码没问题,只是try是多余的

一只三黄鸡 2020-05-30
  • 打赏
  • 举报
回复
还有就是你service的代码逻辑不怎么ok,直接在sql中判断名字是否重复不好吗??你这样操作如果100W个用户,你后台要循环100W次?
一只三黄鸡 2020-05-30
  • 打赏
  • 举报
回复
service去掉try和catch即可
专写bug 2020-05-29
  • 打赏
  • 举报
回复
service里面应该不需要进行try了吧
jinchengyu_ 2019-02-07
  • 打赏
  • 举报
回复
会在发生rollbackFor指定的异常发生后立刻进行回滚,代码如在try catch块中 会执行catch中的代码,如果有finally 还会执行finally中的代码,回滚指的是当前事务不进行提交,而不是将数据提交后删除。
unclezh0730 2018-02-27
  • 打赏
  • 举报
回复
引用 15 楼 unclezh0730 的回复:
我印象中,第一个要在service上标注方法开启@Transaction,第二是默认的抛出异常要是RuntimeException才会事务回滚哦。
不好意思 眼瞎 看代码的时候没有仔细看到你声明了Exception回滚
unclezh0730 2018-02-27
  • 打赏
  • 举报
回复
我印象中,第一个要在service上标注方法开启@Transaction,第二是默认的抛出异常要是RuntimeException才会事务回滚哦。
dengjinhmm 2018-02-27
  • 打赏
  • 举报
回复
你色service中把异常捕捉并抛出了 @Transaction注解就会铺捉不到异常, 所以事务并没有回滚
u013672776 2018-02-26
  • 打赏
  • 举报
回复
只要service方法执行时 抛出 rollbackfor 定义的异常及其子类 都会回滚
马扎学长 2018-02-24
  • 打赏
  • 举报
回复
楼主,你确定插入操作回滚了吗?还有你上边说的 “就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊”,我理解为你执行完这段代码后查出了两条,而你贴的图是执行代码之前的。 顺着我的理解说一下,spring默认事务只在发生未被捕获的 runtimeexcetpion时才回滚,你设置为了Exception,这没毛病,但是你在controller里边把他捕获了,spring怎么知道你这里边还有异常呢?所以你这段代码是不会回滚的。
wwang221 2017-06-14
  • 打赏
  • 举报
回复
@love1390700626 就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊
李德胜1995 2017-06-14
  • 打赏
  • 举报
回复
spring默认事务只在发生未被捕获的 runtimeexcetpion时才回滚,你的saveUser(user)方法被你try...catch了,所以无法回滚, 可以选择去掉try...catch

@Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) throws Exception {
        if (user != null && user.getId() != null) {
            userDao.updateUser(user);
        } else {
            // TODO find if there is a repetition, can also use SQL
     
                List<User> allUser = userDao.getUser();
                userDao.insertUser(user);
                for (User _user : allUser) {
                    if (_user.getUsername().equals(user.getUsername()))
                        throw new Exception("The account is exist!");
                } 
        }
    }
或者在catch加上TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

@Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) throws Exception {
        if (user != null && user.getId() != null) {
            userDao.updateUser(user);
        } else {
            // TODO find if there is a repetition, can also use SQL
            try {
                List<User> allUser = userDao.getUser();
                userDao.insertUser(user);
                for (User _user : allUser) {
                    if (_user.getUsername().equals(user.getUsername()))
                        throw new Exception("The account is exist!");
                }
            } catch (Exception e) {
                  TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw e;
            }
        }
    }
  • 打赏
  • 举报
回复
想知道原理的话就得去看底层代码了,我也是个小白
  • 打赏
  • 举报
回复
原理的话我也不知道
  • 打赏
  • 举报
回复
spring的实务配置会在抛出RuntimeException的时候回滚,在你多次往数据库操作的时候,只有全部成功的时候才会顺利通过,不然的话就会全部回滚,个人理解是这样的。
  • 打赏
  • 举报
回复
service 方法在捕获到 RuntimeException 及其子类的异常时才会回滚吧
unclezh0730 2017-06-14
  • 打赏
  • 举报
回复
引用 8 楼 unclezh0730 的回复:
[quote=引用 7 楼 unclezh0730 的回复:] [quote=引用 5 楼 u011318721 的回复:] @love1390700626 就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊
我没明白!!! 首先,你说要出错,是出错,你自己抛异常的,然后你那个insert不是回滚了么?数据库不是本身就有一条数据?怎么会将原先的删除呢?只是本次事务控制中出现的所有事务操作保持一致.但是事务控制不能删除之前的数据呀,不然数据库要怎么存数据?[/quote] 如果你说原先你的数据库没有数据,那你这个抛异常的if条件不满足,异常都没有抛出来,事务不会回滚[/quote] 应该说 抛出的异常不是exception,应为异常不是你throw的,是那个_user.getxxx报错的
Mr_NightRaid 2017-06-14
  • 打赏
  • 举报
回复
好像sping管理事务的时候在service层不能捕获异常,你捕获了异常就不能回滚,你把throw e抛出异常那句去掉的话事务应就该不会回滚的
unclezh0730 2017-06-14
  • 打赏
  • 举报
回复
引用 7 楼 unclezh0730 的回复:
[quote=引用 5 楼 u011318721 的回复:] @love1390700626 就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊
我没明白!!! 首先,你说要出错,是出错,你自己抛异常的,然后你那个insert不是回滚了么?数据库不是本身就有一条数据?怎么会将原先的删除呢?只是本次事务控制中出现的所有事务操作保持一致.但是事务控制不能删除之前的数据呀,不然数据库要怎么存数据?[/quote] 如果你说原先你的数据库没有数据,那你这个抛异常的if条件不满足,异常都没有抛出来,事务不会回滚
unclezh0730 2017-06-14
  • 打赏
  • 举报
回复
引用 5 楼 u011318721 的回复:
@love1390700626 就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊
我没明白!!! 首先,你说要出错,是出错,你自己抛异常的,然后你那个insert不是回滚了么?数据库不是本身就有一条数据?怎么会将原先的删除呢?只是本次事务控制中出现的所有事务操作保持一致.但是事务控制不能删除之前的数据呀,不然数据库要怎么存数据?
加载更多回复(1)

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧