Spring事务管理详解-事务基础

本文于718天之前发表,文中内容可能已经过时。

目前JavaWeb系统的框架容器基本都是使用Spring管理的,其中事务管理也是比较重要的,之前也是看过,网上介绍的文章也很多,但毕竟不是自己的,也借此机会总结下Spring对事务的管理,希望对大家有用。

1.事务基础

1.1.事务的基本概念

数据库事务(Database Transaction):是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 “一荣俱荣,一损俱损”最能体现事务的的思想。也就是这些操作要么所有执行成功,所有执行失败。
数据库事务需要满足4个特性:原子性(Atomic),一致性(Consistency),隔离性(Isolation),持久性(Durabiliy),简称为ACID原则。

  • 原子性:表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才能提交,若事务中的任务一个数据库操作失败,已经执行的任务操作都必须撤销,让数据库返回到初始状态。
  • 一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。如在上超市买东西付款时,从你的账户扣钱,超市的账户价钱,但不管操作是否成功,你和超市的存款总额应是不变的。
  • 隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对对方产生干扰。说白了就是同时存在两个事务一起操作数据时,都会在各自的事务空间中,对数据的操作不会对对方产生干扰。但,各个数据库实现也没有做到完全无干扰,数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。
  • 持久性:一旦事务提交成功后,事务中所有的数据操作都必须持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

上面这些特性,数据的“一致性”是最终目标,其他特性都是为他服务。

1.2.事务并发带来的问题

同一时刻有可能有多个事务访问数据库的同一个资源,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性。总共包括5类,3种数据读取问题(脏读、不可重复读和幻象读)以及2类数据更新问题(第一类丢失更新和第二类丢失更新),下面分别说下

  • 脏读(dirty read)
    事务A读取事务B尚未提交的更改数据,并在这个数据的基础上操作。如果这时正好事务B回滚了,那么事务A读取到数据就是脏数据,也即是脏读。
时间 转账事务A 取款事务B
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 取出500元把余额改为500元
T5 查询账户余额为500元(脏读)
T6 撤销事务余额恢复为1000元
T7 汇入100元把余额改为600元
T8 提交事务

脏读对Oracle中不会发生,因为Oracle数据库使用了数据库版本的机制,在回滚段为数据的每个变化都保存一个版本,使数据的更改不影响数据的读取。

  • 不可重复度(unrepeatable read)
    不可重复读是指事务A读取了事务B已经提交的更改数据。如A在取款事务的过程中,B往改账户转账100元,A两次读取的账户余额发生不一致。
时间 取款事务A 转账事务B
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 取出100元把余额改为900
T6 提交事务
T7 查询账户余额为900元和T4读取的不一致
  • 幻象读(phantom read)
    幻象读和不可重复度类似,即事务A读取事务B提交的新增数据,这时事务A将出现幻象读的问题。幻象读一般发生在计算统计数据的事务中,如:银行系统在同一个事务中,两次统计存款账户的总金额,在两次统计过程中,刚好新增了一个存款账户,并存入100元,这时,两次统计的总金额将不一致。
时间 统计金额事务A 转账事务B
T1 开始事务
T2 开始事务
T3 统计总存款数为1000元
T4 新增一个存款账户,存款为100元
T5 提交事务
T6 再次统计存款数为1100元(幻象读)
  • 不可重复读和幻象读的区别
    不可重复读在于记录的值,即读取到其他已经提交事务的更改数据。
    幻象读在于记录的数量,即读取到其他已经提交事务的新增数据。

数据库的解决方法:
解决不可重复读——添加行级锁
解决幻象读——添加表级锁

  • 第一类丢失更新
    事务A撤销时,把已经提交的事务B的更新数据覆盖了。这种错误可能造成很严重的问题。看下面例子
时间 取款事务A 转账事务B
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 汇入100元把余额改为1100元
T6 提交事务
T7 取出100元把余额改为900元
T8 撤销事务
余额恢复为1000元(丢失更新)
  • 第二类丢失更新
    事务A覆盖事务B已经提交的数据,造成事务B所做操作丢失。

2.事务隔离级别

数据库为了解决1.2节中描述的事务并发问题通常是使用数据库锁机制,但数据库中的锁机制用户直接使用很麻烦,所以数据库提供了自动锁机制。即用户指定相应的事务隔离级别,数据库会添加合适的锁。
ANSI/ISO SQL 92标准定义了4个等级的事务隔离级别,不同事务隔离级别能够解决的数据并发问题的能力是不同的。如下:

隔离级别 脏读 不可重复读 幻象读 第一类丢失更新 第二类丢失更新
READ UNCOMMITED 允许 允许 允许 不允许 允许
READ COMMITED 不允许 允许 允许 不允许 允许
REPEATABLE READ 不允许 不允许 允许 不允许 不允许
SERIALIZABLE 不允许 不允许 不允许 不允许 不允许

事务的隔离级别和数据库的并发性是对立的,两者此增彼涨。使用READ UNCOMMITED隔离级别的数据库拥有最高的并发性和吞吐量,使用SERIALIZABLE隔离级别的数据库并发性和吞吐量最低。

想了解更多技术文章信息,请继续关注wiliam.s Blog,谢谢,欢迎来访!


参考资料
《Spring3.x企业应用开发实战》陈雄华 林开雄著

欣赏此文?求鼓励,求支持!
上一篇