[TOC]
- 事务(Transaction)是访问并可能更新数据库中各项数据项的一个程序执行单元(unit)
- 在关系型数据库中,一个事务由一组SQL语句组成
- 通常称为 ACID 特性
- 一个事务内的操作不可分割,要么全部完成,要么全部失败
- 一个事务,必须使数据库从一个一致性状态 变到 另一个一致性状态,事务的中间态是不能被观察到的
- 并发执行的各个事务之间,不能互相干扰
- 读未提交(read uncommitted)
- 读已提交(read committed),解决脏读
- 可重复读(repeatable read),解决不可重复读
- 串行化(serializable),解决幻读
- 事务一旦提交,对数据的改变就应该是永久性的
- 即操作单一数据库的事务
- 本地事务的ACID特性,直接由数据库提供支持
Connection conn = ... //获取数据库连接
conn.setAutoCommit(false); //开启事务
try{
//...执行增删改查sql
conn.commit(); //提交事务
}catch (Exception e) {
conn.rollback();//事务回滚
}finally{
conn.close();//关闭链接
}
- 即操作多个数据库的事务
- 用于定义事务边界(即定义事务的开始和结束),并在事务边界内对资源进行操作
- 如数据库、文件系统等,并提供访问资源的方式
- 负责分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚等
- 控制一个TM域内、或者跨TM域的分布式应用之间的通信
- 提供CRM的分布式应用节点之间的底层通信服务
- 在DTP本地模型实例中,只由 AP、RM集合、TM组成。
- (1) 表示 AP - RM 的交互接口
- (2) 表示 AP - TM 的交互接口
- (3) 表示 RM - TM 的交互接口
- XA规范定义了 RM - TM 的交互接口(XA Interface)
- XA规范还对两阶段提交协议进行了优化
- 将 提交(commit) 过程划分为 2个阶段(phase)
- TM通知各个RM准备提交它们的事务分支
- RM接收通知,判断当前工作是否可以被提交
- 可以:RM对工作内容进行持久化,再给TM肯定答复
- 不可以:给TM否定答复,并回滚工作内容,然后舍弃该事务分支信息
- RM接收通知,判断当前工作是否可以被提交
- 以 MySQL 为例,第一阶段中,事务管理器向所有涉及到的数据库服务器发出 prepare(准备提交)请求,
- -> 数据库收到请求,执行数据修改和日志记录等处理,
- -> 处理完成后,只是把事务的状态改成 "可以提交",
- -> 把结果返回给事务管理器
- TM根据阶段一各个RM prepare的结果,决定是提交还是回滚事务
- 全都成功:TM 通知所有RM进行提交
- 否则:TM 通知所有RM进行回滚
- 以 MySQL 为例
- 如果所有 prepare 成功,事务管理器会向数据库服务器发出"确认提交"请求
- -> 数据库把事务的 "可以提交" 状态变为 "提交完成"
- -> 返回应答
- 否则,数据库进行回滚
- 如果所有 prepare 成功,事务管理器会向数据库服务器发出"确认提交"请求
- XA 是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁
- TCC 是业务层面的分布式事务,最终一致性,不会一直持有资源的锁
- 2PC中全局事务的ACID特性,是依赖于各个RM的
- 在对数据并行读写很敏感的情况下,本地事务都需将隔离级别设置为 串行化
- 可重复读 不足以保证分布式事务的一致性
- 然而 串行化 是执行性能最低的隔离级别
- 一旦 TM 发生故障,所有 RM 都会一直阻塞
- 尤其在第二阶段,RM仍属于锁定事务资源的状态中,而无法继续完成事务操作
- 就算 TM 是集群,一个 down 掉能选举出另一个,但无法解决 RM 这段时间都是处于阻塞状态的问题
- 阶段二种,当TM向RM发送 commit 请求后,发生了局部网络异常
- 就导致只有部分 RM 收到 commit 请求,这就造成了整个分布式系统出现数据不一致的现象
- 3PC 是 2PC 的改进版本,主要两个改动点
- 在 TM 和 RM 中都引入了 超时机制
- 在阶段一和阶段二之间,插入一个 准备阶段
- TM 向 RM 发送 CanCommit(事务询问) 请求
- RM 收到请求后,可以顺利执行事务则返回 Yes、并进入预备状态,否则返回No
- 如果所有 RM 都响应 Yes
- TM 向 RM 发送 PreCommit(事务预提交) 请求,并进入 Prepared 阶段
- RM 收到请求后,执行事务操作,并将 undo 和 redo 记录到事务日志中
- 成功后,返回 ACK,开始等待最终指令
- 如果有 RM 响应 No,或者等待超时
- TM 向 RM 发送 abort(中断) 请求
- RM 收到请求后(或等待超时),执行事务的中断
- 执行提交
- TM 收到 RM 的 ACK,从 预提交状态 -> 提交状态,并向 RM 发送 doCommit 请求
- RM 收到请求后,执行正式的事务提交,完成后释放所有资源
- RM 向 TM 响应 ACK
- TM 收到所有 RM 的 ACK 响应后,完成事务
- 中断事务
- TM 向所有 RM 发送 abort请求
- RM 收到请求后,利用 PreCommit 中记录的 undo日志执行事务回滚,完成后释放所有资源
- RM 向 TM 响应 ACK
- TM 收到所有 RM 的 ACK 响应后,执行事务的中断
- 该阶段中,如果 RM 无法及时接受到 TM 的 doCommit 或 rebort 请求,即等待超时的情况下,默认执行 commit
- 就可能其他 RM 执行 abort,该节点执行了 commit,造成数据不一致问题
- 相对于 2PC,3PC主要解决单点故障问题,并减少阻塞
- 无论是 2PC 还是 3PC 都无法彻底解决分布式事务的一致性问题