开发者

Springboot中@Transactional注解与异常处理机制方式

目录
  • Springboot @Transactional注解与异常处理机制
  • @Transactional错误集锦以及如何正确使用
    • 原理
    • 添加位置
    • 错误案例
  • 总结

    Springboot @Transactional注解与异常处理www.devze.com机制

    @Transactional注解的方法默认会捕获所有非检查异常,即RuntimeExcandroideption和Error,可以通过括号声明显示指定处理异常类,如Exception.class

    关于异常处理机制:

    当代码抛出异常时,异常处理的优先级如下:

    • try-catch 块:如果在代码中使用了 try-catch 块来捕获异常,异常将会首先被 try-catch 块捕获并处理。只有在 try-catch 块中未处理(重新抛出)异常时,异常才会继续传播。
    • @Transactional:如果异常从 try-catch 块中传播出来,Spring 的事务管理器(由 @Transactional 注解管理)会捕获异常并决定是否回滚事务。事务处理之后,异常继续传播。
    • @ExceptionHandler:最后,异常会被全局异常处理器(由 @ControllerAdvice 和 @ExceptionHandler 注解管理)捕获并处理。

    因此,对于手动捕获的异常,需要手动将其抛出才会被@Transactional处理器捕获,全局处理器的优先级最后,除了特殊的异常可能需要调整传播顺序,大部分不需要考虑其影响。

    @Transactional错误集锦以及如何正确使用

    原理

    @Transactional 是声明式事务管理 编程中使用的注解,通过Spring AOP在注解修饰方法的前后织入事务管理的实现语句,所以开发者只需要通过一个注解就能代替一系列繁琐的事务开始、事务关闭等重复性的编码任务。

    添加位置

    • 接口实现类或接口实现方法上,而不是接口类中。
    • 访问权限:public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。
    • 系统设计:将标签放置在需要进行事务管理的方法上,而不是放在所有接口实现类上:只读的接口就不需要事务管理,由于配置了@Transactional就需要AOP拦截及事务的处理,可能影响系统性能。

    错误案例

    1.同一个类中调用

    public class A {
        
        public void methodA() {
            methodB();
            
            /javascript/ 其他操作
        }
    
        @Transactional
        public void methodB() {
            // 写数据库操作
        }
        
    }

    上面案例是错误的基于Spring Aop的拦截机制,将会忽略事务。

    解决方式如下:

    @Service@AllArgsConstructorpublic class A {        private B b;        public void methodA() {        b.methodB(javascript);        // 其他操作    }}@Servicepublic class B {
        @Transactional    public void methodB() {        // 写数据库操作    }    }
    

    注意:这里的B类没有用@Autowrire,构造函数用Lombok的@AllArgsConstructor生成 自动注入了。

    2. @Transactional修饰方法不是public

    public class TransactionalMistake {
        
        @Transactional
        private void method() {
            // 写数据库操作
        }
        
    }

    这也是基于Spring AOP实现的注解所要满足的要求。这个最简单, 直接把方法访问类型改成public即可。

    3. 不同的数据源

    public class TransactionalMistake {
    
        @Transactional
        public void createOrder(Order order) {
            orderRepo1.save(order);
            orderRepo2.save(order);
        }
    
    }

    上面这个例子里的orderRepo1和orderRepo2是连接的两个不同数据源。

    默认情况下,这种跨数据源的事务是不会成功的。

    如果要在多个数据源之间实现事务,那么可以引入JTA。

    4. 回滚异常配置不正确

    默认情况下,仅对RuntimeException和Error进行回滚。

    如果不是的它们及它们的子孙异常的话,就不会回滚。

    如果不是RuntimeException,但也希望触发回滚,那么可以使用rollbackFor属性来指定javascript要回滚的异常。

    public class TransactionalMistake {
    
        @Transactional(rollbackFor = XXXException.class)
        public void method() throws XXXException {
    
        }
    
    }

    5. 数据库引擎不支持事务

    spring.jpa.database-platform=org.hibernate.dialect.mysql5InnoDBDialect

    这里的spring.jpa.database-platform配置主要用来设置hibernate使用的方言。

    这里特地采用了MySQL5InnoDBDialect,主要为了保障在使用Spring Data JPA时候,Hibernate自动创建表的时候使用InnoDB存储引擎,不然就会以默认存储引擎MyISAM来建表,而MyISAM存储引擎是没有事务的。

    Springboot中@Transactional注解与异常处理机制方式

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜