10分钟学会Spring的事务管理机制

2019-01-06  本文已影响0人  谦卑王生

前言

在互联网数据库的使用中,对于那些电商和金融网站,最关注的内容毫无疑问就是数据库事务,因为对于人们商品的交易和库存以及金融产品的金额,是不允许发生错误的。但是它们面临的问题是,热门产品或金融产品上线销售瞬间可能面对的高并发的场景。那么在Spring中采用哪些事务机制处理这些高并发场景的呢?

Spring事务管理

常见的Spring事务管理有以下两种:

1. 编程式事务管理
2.声明式事务管理
  1. 基于XML配置文件的实现;
    2.在业务方法上加上@Transactional注解,将事务规则应用到业务逻辑中。

对于声明式事务,是使用@Transactional进行标注的,这个注解可以标注在类或方法上,当它标注在类上时,代表这个类的所有公共的(public)非静态的方法都将启动事务功能。在@Transactional中,还允许配置许多的属性,如事务的传播行为和隔离级别,以及异常类型,从而确定方法发生什么异常下回滚事务什么异常下不回滚事务等。这些配置内容,是在Spring IoC容器在加载时就会将这些配置信息解析出来,然后把这些信息存到事务定义器(TransactionDefinition接口的实现类)里,记录哪些类或者方法需要启动事务功能,采取什么策略去执行事务。在这个过程中,我们需要做的就是给需要事务的类或方法中加上@Transactional注解和配置其属性而已。
有了@Transactional的配置,Spring就会知道在哪里启动事务机制,其约定流程如下图所示:


image.png
3.隔离级别

当前互联网应用时刻面临着高并发的环境,如商品库存,时刻都是多个线程共享的数据,这样就会在多线程的环境中扣减商品库存。对于数据库而言,就会出现多个事务同时操作同一记录的情况,这样会引起数据出现不一致的情况,便是数据的丢失更新(Lost Update)问题。

数据库事务的知识

数据库事务具有以下4个基本特性,也就是著名的ACID。

第一类丢失更新
时刻 事 务 1 事 务 2
T1 初始库存100 初始库存100
T2 扣减库存,余99 ——
T3 —— 扣减库存,余99
T4 提交事务,库存变为99
T5 回滚事务,库存100

可以看到,T5时刻事务回滚,导致原本库存为99的变为了100,显然事务2的结果就丢失了,这就是一个错误的值,类似的,对于这样一个事务提交而引发的数据不一致的情况,我们称为第一类丢失更新

第二类丢失
时刻 事 务 1 事 务 2
T1 初始库存100 初始库存100
T2 扣减库存,余99 ——
T3 —— 扣减库存,余99
T4 —— 提交事务,库存为99
T5 提交事务,库存变为99 ——

注意在T5时刻提交的事务。因为在事务1中,无法感知事务2 的操作,这样它就不知道事务2已经做了修改,因此它依旧认为这只是发生了一笔业务,所以库存更新变成了99,而这个结果又是一个错误的结果。这样T5时刻事务1提交的事务,就会引发事务2提交结果的丢失,我们把这样的多个事务的提交引发丢失更新的称为第二类丢失更新

为处理第二类丢失更新引发的错误,提出了事务的隔离级别,常见的隔离级别有以下4种:

1.未提交读

未提交读(read uncommitted)是最低的得力级别,其含义是允许一个事务读取另一个事务没有提交的数据。未提交读是一种危险的隔离级别。所以我们一般在实际的开发中应用不广,但是它的优点在于并发能力高,适合那些对数据一致性没有要求而追求高并发的场景,它的最大坏处是出现脏读。

脏读现象
时刻 事 务 1 事 务 2 备 注
T0 ....... ........ 商品库存初始化为2
T1 读取库存为2
T2 扣减库存 库存为1
T3 扣减库存 库存为0,读取事务1为提交的数据
T4 提交事务 库存保存为0
T5 回滚事务 因为第一类丢失更新已经克服,所以不会回滚为2,库存为0,结果错误

因为采用未提交读,所以事务2可以读取事务1为提交的库存数据为1,这里当它扣减库存后则数据为0,然后它提交了事务,库存就变成了0,而事务1在T5时刻回滚事务,因为第一类丢失更新已经被克服,所以它不会将库存回滚到2,那么最后的结果就变成了0,所以就出现了这样的错误,脏读一般是比较危险的隔离级别,在我们实际应用中采用的不多。

未待完续,请持续关注~

上一篇下一篇

猜你喜欢

热点阅读