深入理解spring事务!一文讲明白Spring事务到底干了什么?为什么你设置的Spirng的事务传播特性不生效?怎么理解Spring事务!

注:
大家好我是妈妈的好大儿,
笔者联系方式
QQ:3302254385
微信:yxc3302254385
交个朋友!
创作不易,三连十分感谢!!!

为什么会去写这样的一篇博客?

很多面试官在面试的时候都会去问到!

  1. 数据库的事务!!事务是什么东西?
  2. 事务的隔离级别
  3. ACID原则
  4. spring事务的实现方式
  5. Spring事务的传播特性!!
  6. 等等等!!

对于这些面试题相信大家都已记得滚瓜烂熟了!!!基本上80%都会被问道!!!在工作中也是100%会用到我们的事务!!!
可是你真的理解,事务吗?spring是怎样去实现事务!!去拓展出事务的传播特性呢??

案列演示 正常情况和疑问点

正常情况:

@Service
public class TestService  {


   

    @Resource
    private ArticleDirectoriesMapper articleDirectoriesMapper;

    /**
     * 插入一个文章目录
     */
    @Transactional
    public void methodA(){
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(111L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
        methodB();
        System.out.println(1/0);

    }

    /**
     * 插入一个文章目录
     */
    public void methodB(){
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(222L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
    }


}

相信大家经常会编写这样的代码,使用默认的spring提供的事务的传播特性(加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务。默认情况下,参与的事务将加入外部作用域的特征,而忽略本地隔离级别),A方法和B方法将作为一个整体进行事务的提交与回滚!!!!

产生疑问的情况:

@Service
public class TestService  {
    
    @Resource
    private ArticleDirectoriesMapper articleDirectoriesMapper;

    /**
     * 插入一个文章目录
     */
    @Transactional
    public void methodA(){
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(111L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
        methodB();
        System.out.println(1/0);

    }

    /**
     * 插入一个文章目录
     */
    //此时的事务隔离级别为  (以非事务方式执行,如果存在事务则抛出异常)
    @Transactional(propagation = Propagation.NEVER)
    public void methodB(){
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(222L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
    }

    
}

这里我们设置了方法B的事务的隔离传播特性为(以非事务方式执行,如果存在事务则抛出异常)
但是调用完A方法后,B方法插入的数据也回滚了!!! 代表A方法和B方法在同一事务,但是这里我们的B方法的传播特性明明是,有事务就抛出异常!!!为什么会失效呢???难道是spring的问题???

问题分析与解决

这里就涉及到Spring的bean的生命周期!!!!
我们在使用xxService的bean对象,执行业务层操作时,如果xxxxService中有事务方法,其实是需要Spring帮我们进行了动态代理的也就是进行Aop,来完成我们的事务执行!!!
所以要保证我们事务的生效,必须使用我们的代理对象!!!

在这里插入图片描述
其实在我们使用Spring执行事务的时候,它会在我们的方法上执行,

    @Transactional
    public void methodA(){
        //开启connection
        //setAutoCommit(false)设置是否自动提交
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(111L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
        methodB();
        System.out.println(1/0);
        //提交事务
    }

刚刚我们从methodA中调用methodB方法,相当于this.methodB方法,其实它并没有使用Spring的代理对象!!!也就导致我们设置的事务传播特性失效!!!

    @Transactional
    public void methodA(){
        //开启connection
        //setAutoCommit(false)设置是否自动提交
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(111L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
        this.methodB();
        System.out.println(1/0);
        //提交事务
    }

为了解决这个事务传播特性设置失效的问题,我们只需要使用代理对象即可!!解决!!!

@Service
public class TestService  {

    @Resource
    private ArticleDirectoriesMapper articleDirectoriesMapper;
	
	//注入自身的代理对象  
    @Autowired
    TestService testService;

    /**
     * 插入一个文章目录
     */
    @Transactional
    public void methodA(){
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(111L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
        testService.methodB();
        System.out.println(1/0);
    }

    /**
     * 插入一个文章目录
     */
    //此时的事务隔离级别为  (以非事务方式执行,如果存在事务则抛出异常)
    @Transactional(propagation = Propagation.NEVER)
    public void methodB(){
        ArticleDirectoriesDO articleDirectoriesDO = new ArticleDirectoriesDO().setArticleId(222L);
        articleDirectoriesMapper.insertOneLevel(articleDirectoriesDO);
    }
  }

看效果
为标记为传播’never’的事务找到现有事务 ,事务传播特性设置成功!!!
在这里插入图片描述

总结

如果理解了,事务是通过spring进行Aop,进行动态代理从而实现的结果!!!那么和面试官谈起来也就更会有谈资而不是一味的死记一些概念!!!毫无意义

其实事务的实现也需要数据库的支持,如Mysql的InnoDB,OLTP类支持事务-----MyISAM,Archive不支持事务,这些是需要数据引擎去实现完成的!!!而并分Spring去做!!!
关于数据库的基础事务知识我们就不在复习了,这里主要就是讲到怎么去理解Spring这个容器,去帮你做了什么事情,应该怎么用才合理,那么我们来简单的复习一遍SpringBean的生命周期

  • Spring扫描class得到BeanDefinition
  • 根据得到的BeanDefinition去⽣成bean,推断构造方法
    • 默认使用无参构造方法
    • 通过@Autowired注解可以指定,Spring调用具体的某个构造方法
    • 如果有多个构造却没有无参构造报错,如果只有一个有参构造会使用这个有参构造
    • 如果构造方法有参数,spring会先通过类型,再通过属性名来自动注入对象
  • 根据推断出来的构造⽅法,反射,得到⼀个对象(暂时叫做原始对象)
  • 属性填充(如:@Autowired注入其他bean引用)(依赖注⼊)
  • 如果原始对象中的某个⽅法被AOP了,那么则需要根据原始对象⽣成⼀个代理对象
  • 生成切入点的代理对象
  • bean(代理对象)
  • afterPropertiesSet(如:@PostConstruct)
  • 把最终⽣成的代理对象放⼊单例池(源码中叫做singletonObjects)中,下次getBean时就直接从单例池拿即可
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值