Home
avatar

yuanjh

java微服务03_SpringBoot常见问题

参考教程:
Spring Boot 2.x基础教程:https://blog.didispace.com/spring-boot-learning-2x/
Spring Boot:https://blog.didispace.com/categories/Spring-Boot/

事务

事务不生效的原因

常见情况
01、数据库引擎不支持事务
02、异常被你的 catch“吃了”导致@Transactional失效
03、@Transactional 应用在非 public 修饰的方法上
04、同一个类中方法调用,导致@Transactional失效
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。
那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
05、@Transactional 注解属性 propagation 设置错误 这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。 TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。 06,@Transactional 注解属性 rollbackFor 设置错误 rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor属性。

@Transactional 应该加到什么地方,如果加到Controller会回滚吗?

@Transactional 加到Controller层也是生效的,但是为了规范起见,还是加到service层上。

@Transactional 注解中用不用加rollbackFor = Exception.class 这个属性值

默认情况下,当程序发生 RuntimeException 和 Error 的这两种异常的时候事务会回滚,但是如果发生了checkedExcetions ,如fileNotfundException 则不会回滚,所以 rollbackFor = Exception.class 这个一定要加!

为什么catch了异常,但事务还是回滚

事务调用嵌套问题具体结果如下代码:

/**
     * 同类中在方法a中调用b
     * a没有事务,b有 ,异常发生在b中 不会回滚
     */
    @RequestMapping("/a1")
    public void a1(){
        transactionalService.a1();
    }

    /**
     * 同类中在方法a中调用b
     * a没有事务,b有 ,异常发生在a中 不会回滚
     */
    @RequestMapping("/a2")
    public void a2(){
        transactionalService.a2();
    }
    /**
     * 同类中在方法a中调用b
     * a有事务,b没有 ,异常发生在b中 会回滚
     */
    @RequestMapping("/a3")
    public void a3(){
        transactionalService.a3();
    }
    /**
     * 同类中在方法a中调用b
     * a有事务,b没有 ,异常发生在a中 会回滚
     */
    @RequestMapping("/a4")
    public void a4(){
        transactionalService.a4();
    }
    /**
     * 同类中在方法a中调用b
     * a有事务,b也有 ,异常发生在b中 会回滚
     */
    @RequestMapping("/a5")
    public void a5(){
        transactionalService.a5();
    }
    /**
     * 同类中在方法a中调用b
     * a有事务,b也有 ,异常发生在a中 会回滚
     */
    @RequestMapping("/a6")
    public void a6(){
        transactionalService.a6();
    }


    /**
     *a类中调用b类中的方法
     * a中有事务,b中也有 会回滚
     *
     */
    @RequestMapping("/b5")
    public  void b5(){
        transactionalService.b5();
    }

    /**
     *a类中调用b类中的方法
     * a中有事务,b中没有 会回滚
     *
     */
    @RequestMapping("/b6")
    public  void b6(){
        transactionalService.b6();
    }

    /**
     *a类中调用b类中的方法
     * a没有事务,b中有 不会回滚
     *
     */
    @RequestMapping("/b7")
    public  void b7(){
        transactionalService.b7();
    }

    /**
     *a类中调用b类中的方法
     * a没有事务,b中没有 不会回滚
     *
     */
    @RequestMapping("/b8")
    public  void b8(){
        transactionalService.b8();
    }

总结:如果在a方法中调用b方法不管是不是a和b是不是在同一个类中,只要a方法中没有事务,则发生异常的时候不会回滚,即:当a无事务时,则a和b均没有事务,当a有事务时,b如果有事务,则b事务会加到a事务中,二者为同一事务!

总结

springboot中默认是开启事务的,在service层的方法加上@Transactional(rollbackFor = Exception.class) 注解即可实现事务 如果在方法a中调用方法b 如果要实现事务,则只需要在方法上加上@Transactional(rollbackFor = Exception.class) 即可!
如果业务需要,一定要抛出checked异常的话,可以通过rollbackFor属性指定异常类型即可。

JTA实现多数据源的事务管理

使用JTA实现多数据源的事务管理:https://blog.didispace.com/spring-boot-learning-24-3-12/ 在Spring Boot 2.x中,整合了这两个JTA的实现: Atomikos:可以通过引入spring-boot-starter-jta-atomikos依赖来使用 Bitronix:可以通过引入spring-boot-starter-jta-bitronix依赖来使用

Async实现异步调用

Spring Boot使用@Async实现异步调用:使用Future以及定义超时:https://blog.didispace.com/springbootasync-4/ Spring Boot使用@Async实现异步调用:ThreadPoolTaskScheduler线程池的优雅关闭:https://blog.didispace.com/springbootasync-3/

@Bean("taskExecutor")
public Executor taskExecutor() {
	ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
	executor.setPoolSize(20);
	executor.setThreadNamePrefix("taskExecutor-");
	return executor;
}

@Async("taskExecutor")
public void doTaskOne() throws Exception {
	log.info("开始做任务一");
	long start = System.currentTimeMillis();
	log.info(stringRedisTemplate.randomKey());
	long end = System.currentTimeMillis();
	log.info("完成任务一,耗时:" + (end - start) + "毫秒");
}

加密配置中的敏感信息

Spring Boot 2.x基础教程:加密配置中的敏感信息:https://blog.didispace.com/spring-boot-learning-2-1-5/

MyBatis的多数据源

Spring Boot 2.x基础教程:MyBatis的多数据源配置:https://blog.didispace.com/spring-boot-learning-21-3-9/

参考

为什么catch了异常,但事务还是回滚了?:https://mp.weixin.qq.com/s?__biz=MzAxODcyNjEzNQ%3D%3D&idx=2&mid=2247535985&sn=71f31a9e35843aa0c82402780fdc9cb8
spring声明式事务 @Transactional 不回滚的多种情况以及解决方案:https://blog.csdn.net/weter_drop/article/details/103582742 为什么加了@Transactional注解,事务没有回滚?:https://blog.didispace.com/transactional-not-rollback/
使用事务(@Transactional)可能出现的问题:https://blog.csdn.net/zero__007/article/details/112046592#t5

java spring系列
java_spring01读书要点
java_spring02ioc有什么优点
java_spring04Autowired与Resource差异解析
java_spring05循环依赖
java_spring06AOP
java_spring07mybatis学习要点
java_微服务01SpringCloud基础
java_微服务02SpringBoot学习笔记
java_微服务03SpringBoot常见问题
java_微服务04SpringCloud学习笔记
java_微服务06SpringCloud常见问题之Eureka
java_微服务07SpringCloud常见问题之Feign
java_微服务08SpringCloud常见问题之Hystrix
java_微服务09SpringCloud常见问题之Ribbon
java_微服务10SpringCloud常见问题之Zuul
java_微服务11SpringCloud其他问题

java微服务