zoukankan      html  css  js  c++  java
  • @Transaction中的rollbackFor属性一定需要声明出来吗?

    前言

    ​ 在阿里巴巴的内部JAVA开发规范手册中,方法【function】需要在Transactional注解指定rollbackFor或者在方法中显示的rollback。一开始不知什么用意,只知道只要给方法
    添加@Transaction注解,如果出现了异常,spring会将该方法涉及的sql增删改操作进行回滚。今天特意找了资料解惑。

    疑问?

    @Transaction中的rollbackFor属性一定需要声明出来吗?

    异常的分类

    先来看看异常的分类

    ​ 只有继承了Throwable类的异常,才能够被Java虚拟机识别并抛出。

    The {@code Throwable} class is the superclass of all errors and
    * exceptions in the Java language. Only objects that are instances of this
    * class (or one of its subclasses) are thrown by the Java Virtual Machine or
    * can be thrown by the Java {@code throw} statement. Similarly, only
    * this class or one of its subclasses can be the argument type in a
    * {@code catch} clause.
    

    Throwable下分为ExceptionError,对于Spring实现的事务框架而言,如果方法抛出了Error类型的错误是支持回滚的。但是对于Exception则不完全相同。

    Exception再分类

    ​ Exception作为异常,又可细分为运行时异常RuntimeException非运行时异常

    像上图中罗列的运行时异常等:

    • NullPointerException:空指针异常
    • ArithmeticException:算数运算异常
    • ClassCastException:类型强制转换异常
    • IndexOutOfBoundsException:下标越界异常
    • NumberFormatException:数字格式异常

    非运行时异常等:

    • IOException:IO异常
    • SQLException:SQL异常

    Exception 再再分类

    • 可检查的异常(checked Exception):Exception下除了RuntimeException外的异常
    • 不可检查的异常(unchecked Exception):RuntimeException及其子类和错误(Error)

    对于不可检查的异常而言

    如果不对不可检查的异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止

    如果不想终止,则必须捕获所有的不可检查的异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。

    示例:

    @Override
    @Transactional
    public void save(EditExamPaperReq req)  {
            TExamPaper tExamPaper = VOUtil.from(req,TExamPaper.class);
            examPaperDao.insert(tExamPaper);
        	int a = 1 / 0;
            throw new RuntimeException();
    }
    

    ​ 在上面的示例中,我没有指定rollbackFor属性,不管我是产生了什么运行时异常,只要产生的是不可检查的异常,那么spring的事务框架肯定就会帮我把该方法中涉及到的DML语句进行回滚。不相信的读者可以自行试验。

    对于可检查的异常而言

    ​ 对于可检查的异常,比如IOException,java编译器会强制要求我们对相关代码进行try{}catch{}操作,再将捕捉到的异常是抛出还是自行处理。

    示例一:

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(EditExamPaperReq req) throws Exception {
            TExamPaper tExamPaper = VOUtil.from(req,TExamPaper.class);
            examPaperDao.insert(tExamPaper);
        try {
            throw new Exception();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    

    在上面的代码中,如果我们在catch中没有将异常抛出throw e,意味着对这块代码进行了自定义处理; 那么即使声明了rollbackFor = Exception.class,那对于spring提供的事务框架来说,它没有拦截到Exception,所以不会将insert语句进行回滚。

    示例二:

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void save(EditExamPaperReq req) throws Exception {
            TExamPaper tExamPaper = VOUtil.from(req,TExamPaper.class);
            examPaperDao.insert(tExamPaper);
        try {
            throw new Exception();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    
    public class ServiceException extends RuntimeException {
    

    上面例子rollbackFor拦截的是自定义的RuntimeException,意味着告诉spring,指定它要拦截的是ServieException异常,除此之外的异常,都不进行处理。即使catch代码块抛出的是可检查的Exception异常,但spring事务框架也不会帮该方法的insert操作进行回滚。

    总结

    spring的事务框架会根据rollbackFor属性对指定的异常进行拦截处理:

    • 当没有只当rollbackFor属性时,spring事务框架需要拦截所有的向外抛出的异常
    • 当指定了rollbackFor属性时,spring事务框架只会对属性中指定的异常进行拦截
    /**
     * Defines zero (0) or more exception {@link Class classes}, which must be
     * subclasses of {@link Throwable}, indicating which exception types must cause
     * a transaction rollback.
     * <p>By default, a transaction will be rolling back on {@link RuntimeException}
     * and {@link Error} but not on checked exceptions (business exceptions). See
     * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}
     * for a detailed explanation.
     * <p>This is the preferred way to construct a rollback rule (in contrast to
     * {@link #rollbackForClassName}), matching the exception class and its subclasses.
     * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}.
     * @see #rollbackForClassName
     * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
     */
    Class<? extends Throwable>[] rollbackFor() default {};
    

    查看rollbackFor的文档说明,该属性值默认是一个空数组,可以声明0个或多个Exception类。之所以有这个属性,是为了能够对指定的Exception类进行拦截。也就是说是一个拦截异常的规则而已。并需要一定要在使用@Transaction注解时添加进来!

  • 相关阅读:
    201621123059《Java程序设计》第二周学习总结
    学习计划表
    201621123059《java程序设计》第一周学习总结
    C语言I作业06
    C语言I博客作业05
    C语言I博客作业04
    志勇的C语言I博客作业03
    志勇的C语言I博客作业02
    志勇的第一周作业
    pdf文件完美转换技巧分享
  • 原文地址:https://www.cnblogs.com/process-h/p/15027950.html
Copyright © 2011-2022 走看看