Spring-基于配置的JDBC事务和事务的传播行为

1.什么是数据库事务,几种隔离等级下的数据库事务介绍

2.什么是事务的传播行为?几种传播行为的特点测试

1.数据库事务介绍,几种隔离等级下的事务特点

一、什么是数据库事务
事务是一系列作为一个逻辑单元来执行的操作集合。它是数据库维护数据一致性的单位,它将数据库从一致状态转变为新的一致状态,指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。举个例子,张三通过网上银行向李四转账1000块钱,但是期间由于网络原因,张三转账的操作成功了,但是李四的网络不好,倒置没有收到这笔钱,那么这个时候我们就不应该让张三账户上少这1000块钱,因为收款这一操作失败了,整个事务(转账和收款)都要失败,恢复到最初的状态。
事务有以下几个特性:

  • 原子性:即一个事务当中的多个操作是不可分割的,它们被作为一个整体对待。
  • 一致性:一个事务中的操作的状态必须保持一致,一个操作失败了,那么其它的操作都要失败,要么都成功,要么都失败。
  • 隔离性:多个事务之间要相互隔离,不应该被其它事务打扰到,数据库提供了几种事务的隔离级别,稍后介绍。
  • 持久性:事务一旦提交到数据库中,那么这个操作就是永久的,对数据库的数据的改变就是永久的。

二、数据库的隔离级别
在介绍数据库的隔离级别之前,我们先要了解并发地对数据库进行操作时会有什么问题出现:

  • 脏读:即读取到在数据库事务中还没有被提交地数据。
  • 不可重复读:第一次读到的数据库数据与第二次读到的数据不一致。请注意,这个问题大部分时候可以允许的,因为不会对我们的操作产生什么影响。
  • 幻读:往数据库插入或者删除记录时,前后两次获取的记录数不一致。这个问题在大部分条件下也是允许出现的。

相应的,数据库的隔离级别可以一一对应的解决上述问题:

  • 读未提交(READ UNCOMMITTED):在该隔离级别下,将读取到没有被提交的数据。我们可以实验一下:
    开启一个数据库会话,将隔离等级设置到read uncommitted,然后开启事务。将一个字段price的值由原来的200改为300。但是注意,我们没有提交事务。
    在这里插入图片描述

打开另一个数据库会话,设置隔离等级为读未提交。开启事务,再去读price字段的值,发现读到了300,即读到了没有被提交的数据。

在这里插入图片描述
此隔离等级下没有解决任何的并发读写问题。

  • 读已提交(read committed):在此隔离等级下,只有被提交的事务的数据才能被我们正确的读取到。同样的开启测试验证我们的想法。

在这里插入图片描述
设置隔离级别是读已提交,将price修改位300,但是注意,我们没有提交事务!!!
打开另一个数据库会话,跟上述设置一样。同时读取被修改字段的值。
在这里插入图片描述
可以发现,我们读到的price=200,没有改变。因为修改price的事务没有提交,接下来我们提交。
在这里插入图片描述
再去读取一次该字段的值:
在这里插入图片描述
发现这个时候读取到的数据已经改变了。该隔离等级下可以解决脏读问题。

  • 可重复读(repeatable read):在该隔离等级下,读取到的数据值与第一次读到的值保持一致。即使被修改了,也不会影响我们读到的字段值。
    开启测试,验证是否正确。
    由于mysql数据库的默认隔离等级就是可重复读,所以我们不需要再去设置隔离等级。
    在这里插入图片描述
    开启事务,读取到price的值是200。打开另一个会话,开启事务,修改price的值是400并且提交。再读一次。
    在这里插入图片描述
    在这里插入图片描述
    发现读到的值仍然是200,这就验证了上述的论述。该隔离登记下,可以解决不可重复度的问题。

  • serializable(串行化):在该隔离登记下,将解决上述的所有问题,但是速度非常漫,效率低下。

2.什么是事务的传播行为和几种传播类型的实验。

一、事务的传播行为定义

当多个有事务的方法互相调用时,这些事务如何在这些方法之间传播,这些事务的方法该如何运行。是不是很抽象?那么我们可以通过接下来的实验来帮助我们理解什么是传播行为。

先了解一下传播行为的分类:

  1. REQUIRED:即当一个事务在另一个事务的方法内运行时,如果子事务有事务,那么就在当前方法运行,如果没有,那么子事务就会新建一个事务在方法内运行。
  2. REQUIRES_NEW:当前方法必须开启新的事务,并把原来的方法暂时挂起
  3. SUPPORTS:如果有事务在运行,那么就运行在事务内,否则可以不运行在事务内
  4. NOT_SUPPORTS:当前方法不应该运行在事务中,如果有事务,那么立即将它挂起
  5. MANDATORY:当前方法必须运行在事务内部,如果违反了上述原则,那么抛出异常,与3对比

最常用的就是REQUIRED和REQUIRES_NEW。

那么就来进行测试吧!

 @Transactional(propagation = Propagation.REQUIRED)  //告诉Spring这个方法要添加事务
    public void checkout(String username,String isbn){
        bookDao.updateStock(isbn);
        int price = bookDao.getPrice(isbn);
        bookDao.reduceBalance(username, price);

        System.out.println("结账成功");

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updatePrice(String isbn,int price){
        bookDao.updatePrice(isbn,price);
        System.out.println(this.getClass());
    }

设置两个方法的传播方式都是REQUIRED,在一个新的事务方法中运行。一个用来更新价格,一个用来结账(余额减少,书库存减少)

操作之前的数据库字段值:
在这里插入图片描述
在这里插入图片描述

 @Transactional
    public void mulTransaction(){

        bookService.updatePrice("ISBN-002", 200);
        bookService.checkout("Tom", "ISBN-002");

    }

创建测试方法运行mulTransaction()方法,结果如下:
在这里插入图片描述

在这里插入图片描述
两个事务方法都执行成功。

下面我们在mulTransaction方法内设置异常,查看结果。(这个操作不修改上述修改后的表).

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
没有发生改变。
原因:
因为我们设置更新价格和结账的事务的传播行为都是REQUIRED,所以它们搭载的都是同一个事务,一个失败,全部都要失败。

接下来设置结账的事务传播行为是REQUIRES_NEW。保留异常,那么继续测试。

在这里插入图片描述
在这里插入图片描述
可以看到结账操作成功了,但是更新价格的操作成功不了。
原因:因为我们设置结账的操作是REQUIRES_NEW,那么就相当于开启新事务,结账操作的成败已经与整个操作的是否成功无关。

 /**
     * multx(){
     *
     *     //REQUIRED
     *     A(){
     *     //REQUIRES_NEW
     *         B(){}
     *         //REQUIRED
     *         C(){}
     *     }
     *     //REQUIRES_NEW
     *     D(){
     *     //REQUIRED
     *         E(){
     *         //REQUIRES_NEW
     *             F(){
     *
     *                 10/0;  (D,F,G,E,A,C崩);
     *             }
     *         }
     *         //REQUIRES_NEW
     *         G(){}
     *     }
     *     10/0 (A,C异常,其余成功)
     * }
     */

附上一张较为复杂的事务嵌套,帮助我们理解。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值