今天尝试事务回滚的时候遇到一个问题:
    我在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]
数据库:

解决方案 »

  1.   

    spring的实务配置会在抛出RuntimeException的时候回滚,在你多次往数据库操作的时候,只有全部成功的时候才会顺利通过,不然的话就会全部回滚,个人理解是这样的。
      

  2.   

    @love1390700626 就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊
      

  3.   

    service 逻辑没问题吗?
      

  4.   


    我没明白!!! 首先,你说要出错,是出错,你自己抛异常的,然后你那个insert不是回滚了么?数据库不是本身就有一条数据?怎么会将原先的删除呢?只是本次事务控制中出现的所有事务操作保持一致.但是事务控制不能删除之前的数据呀,不然数据库要怎么存数据?
      

  5.   


    我没明白!!! 首先,你说要出错,是出错,你自己抛异常的,然后你那个insert不是回滚了么?数据库不是本身就有一条数据?怎么会将原先的删除呢?只是本次事务控制中出现的所有事务操作保持一致.但是事务控制不能删除之前的数据呀,不然数据库要怎么存数据?如果你说原先你的数据库没有数据,那你这个抛异常的if条件不满足,异常都没有抛出来,事务不会回滚
      

  6.   

    好像sping管理事务的时候在service层不能捕获异常,你捕获了异常就不能回滚,你把throw e抛出异常那句去掉的话事务应就该不会回滚的
      

  7.   


    我没明白!!! 首先,你说要出错,是出错,你自己抛异常的,然后你那个insert不是回滚了么?数据库不是本身就有一条数据?怎么会将原先的删除呢?只是本次事务控制中出现的所有事务操作保持一致.但是事务控制不能删除之前的数据呀,不然数据库要怎么存数据?如果你说原先你的数据库没有数据,那你这个抛异常的if条件不满足,异常都没有抛出来,事务不会回滚应该说 抛出的异常不是exception,应为异常不是你throw的,是那个_user.getxxx报错的
      

  8.   

    service 方法在捕获到 RuntimeException 及其子类的异常时才会回滚吧
      

  9.   

    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;
                }
            }
        }
      

  10.   

    楼主,你确定插入操作回滚了吗?还有你上边说的 “就是不知道为什么回滚成功了,插入的数据还存在,应该被删除了啊”,我理解为你执行完这段代码后查出了两条,而你贴的图是执行代码之前的。 顺着我的理解说一下,spring默认事务只在发生未被捕获的 runtimeexcetpion时才回滚,你设置为了Exception,这没毛病,但是你在controller里边把他捕获了,spring怎么知道你这里边还有异常呢?所以你这段代码是不会回滚的。
      

  11.   

    只要service方法执行时 抛出  rollbackfor 定义的异常及其子类    都会回滚
      

  12.   

    我印象中,第一个要在service上标注方法开启@Transaction,第二是默认的抛出异常要是RuntimeException才会事务回滚哦。
      

  13.   


    不好意思 眼瞎 看代码的时候没有仔细看到你声明了Exception回滚
      

  14.   

    你色service中把异常捕捉并抛出了  @Transaction注解就会铺捉不到异常, 所以事务并没有回滚
      

  15.   

    会在发生rollbackFor指定的异常发生后立刻进行回滚,代码如在try catch块中 会执行catch中的代码,如果有finally 还会执行finally中的代码,回滚指的是当前事务不进行提交,而不是将数据提交后删除。