基于XML的声明式事务管

发布时间 2023-04-10 22:08:06作者: 晓乎

1. 什么是事务

首先说一下什么是事务。

事务(Transaction)指一个操作,由多个步骤组成,要么全部成功,要么全部失败。

比如我们常用的转账功能,假设A账户向B账号转账,那么涉及两个操作:
(1)从A账户扣钱;
(2)往B账户加入等量的钱。

因为是独立的两个操作,所以可能有一个成功,一个失败的情况。但是因为在这种场景下,必须要保证事务,即要么同时成功,要么同时失败(一个失败需要回滚),不能存在从 A 账户扣钱成功,往 B 账户加入等量钱失败这种情况。

2. 生活中处处可见事务

事务不止存在于数据库中,生活中处处存在事务,只要是涉及多个步骤来完成一件事情时,就涉及到事务。

比如彩礼三金和结婚是一个事务,南方给了价值几十万的彩礼和三金,女方会答应如期将女儿嫁出。如果女方毁约,一般会如数退还彩礼三金。如果遇到蛮横无理的女方,那么就破坏了事务,男方会采取法律或特殊手段要回彩礼三金,强制达到事务。

再如菜市场买东西,一手交钱一手交货;购买机票到最后完成乘机或退还机票(2021年春节因疫情尚未结束倡导就地过年就出现大面积免手续费退还机票的事情);网购下单到满意确收货或不满意退款退货等等。

3.数据库事务

因为数据库操作在日常开发中较为常见,所以在计算机术语中,我们说的事务一般指数据库事务。

数据库事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。

原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。

我们还是用上面“A账户向B账号汇钱”的例子来说明如何通过数据库事务保证数据的正确性。

熟悉关系型数据库事务的都知道从帐号A到帐号B需要6个操作:

(1)从A账号中把余额读出来(500)。
(2)对A账号做减法操作(500-100)。
(3)把结果写回A账号中(400)。
(4)从B账号中把余额读出来(500)。
(5)对B账号做加法操作(500+100)。
(6)把结果写回B账号中(600)。

原子性:
保证1-6所有过程要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。 假如执行到第五步的时候,B账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态。

一致性:
在转账之前,A和B的账户中共有500+500=1000元钱。在转账之后,A和B的账户中共有400+600=1000元。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态,两个状态数据总额时一致的,不能凭空变多或变少。

隔离性:
在 A 向 B 转账的整个过程中,只要事务还没有提交(commit),查询 A 账户和 B 账户的时候,两个账户里面的钱的数量都不会有变化。如果在 A 给 B 转账的同时,有另外一个事务执行了 C 给 B 转账的操作,那么当两个事务都结束的时候,B 账户里面的钱应该是 A 转给 B 的钱加上 C 转给 B 的钱再加上自己原有的钱。

持久性:
一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化(会把数据写入数据库做持久化保存)。

事务是个好多西,因为它符合我们的预期。但是很多场景下,很难保证事务,或者说保证事务需要付出很大的成本。此时就需要我们来权衡利弊,整出一个低成本又符合实际应用场景的设计方案。

4.数据库事务的使用

    对于单条SQL语句,数据库系统自动将其作为一个事务执行,这种事务被称为隐式事务。

    要手动把多条SQL语句作为一个事务执行,使用BEGIN开启一个事务,使用COMMIT提交一个事务,这种事务被称为显式事务,例如,把上述的转账操作作为一个显式事务:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

 

   很显然多条SQL语句要想作为一个事务执行,就必须使用显式事务。

   COMMIT是指提交事务,即试图把事务内的所有SQL所做的修改永久保存。如果COMMIT语句执行失败了,整个事务也会失败。

   有些时候,我们希望主动让事务失败,这时,可以用ROLLBACK回滚事务,整个事务会失败:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
ROLLBACK;

5.基于XML的声明式事务控制

   Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。

   声明式事务控制明确事项:

  • 谁是切点?
  • 谁是通知?
  • 配置切面?

 6. 纯XML声明式事务实现

   (1)导入pom坐标