ACID
偶然看到ACID这个概念,顺手记录 ——
ACID是数据库事务正确执行的四个基本要素缩写 —— 百度百科
| 字母 | 英文 | 中文 |
|---|---|---|
| A | Atomicity | 原子性 |
| C | Consistency | 一致性 |
| I | Isolation | 隔离性 |
| D | Durability | 持久性 |
写在前面
我们要实现一件事情,这需要若干步的操作,不妨视其为“事务”。比如有人给我转账,那么要先从对方账户扣款,然后我的账户钱增加(当然,复杂点可能还有其他的 check 等操作)
再举例 —— Player 使用 500 金购买武器
- 玩家金币减少 500
- 玩家背包增加武器
- 写入资产流水
- 记录购买请求已经完成
在业务层面上,这一操作序列顺利完整的完成之后即表示玩家成功购买了武器
当然,此处可能中途某一步会失败,导致出错,就需要 Rollback
Atomicity
原子性,在多线程那块已经说过很多了 —— 把一个事务视作不可分割的整体,要不然全部操作成功,要不然全部失败,不允许存在部分成功的状态,all-or-nothing(原子嘛,不过既然是“视作”,说明只是从表达和观察上来看是整体,倒不一定是真的操作无法继续细分)
假设玩家购买武器不具有原子性,那么部分成功——玩家扣了 500 金;其他失败 —— 玩家不成功购买到了武器
那么肯定要被喊“退钱!”
所以具有原子性的事务会保证要不然就是扣款成功购买成功,要不然就是扣款失败也没买到武器。不会出现其他情况
原子性主要解决的是:
- 执行到一半时程序崩溃;
- 某一步操作失败;
- 数据库连接突然中断;
- 后续操作违反约束;
- 业务流程只完成一半。
常见实现 —— (挖坑
Consistency
Consistency,一致性,说的玄幻一点 ——
事务执行前后,系统必须满足预先定义的数据规则和业务约束
说的简单点,就是要保证我们的系统在事务执行前后都是合法的状态(在执行事务的时刻可能会出现非法的中间状态,但是不重要,执行开始和结束的时刻必须保证合法!)
例子 ——
转账的时候(没有手续费),我们的资金总和一定是确定的,不能转账后忽然两人的紧闭总额变多或者变少,这就很神秘了(
Isolation
隔离性,有点类似并发的时候处理竞态时候的感觉
比如说多个事务同时在对一个数据库进行读写,那么事务是否是读到了“脏数据”呢?或者其他比如幻读等
比如购票,现在仅剩一张票,但 A 和 B 同时下单,那么应当是谁买到票了呢?如果没有做隔离,则A下单的时候发现有余票,B 也是,那么就可能会售出两张票
Durability
持久性,事务提交之后,保证这笔事务不会因为崩溃而丢失。
说的比较玄乎,举个简单例子 ——
假设数据库执行
1. 在内存里把金币从 1000 改成 500
2. 在内存里加入道具
3. 马上向客户端返回“成功”
4. 准备稍后写入磁盘在第 3 步和第 4 步之间突然断电:
内存内容全部消失重启后数据库只能读到磁盘上的旧数据:
金币:1000
背包:无道具所以写入内存并等于实现持久化,我们要保证返回“Commit 成功”信息的时候,关键的信息不会因为一些错误而丢失
当然,此处的错误肯定不是指所有错误,而是我们声明可以抵御的故障问题,常见的比如 ——
- 数据库进程突然崩溃;
- 操作系统崩溃;
- 服务器异常重启;
- 正在写入时突然断电。
常见的核心实现是WAL —— Write-Ahead Logging,预写日志
总结
用游戏商城购买来总结 —— 下面是一个“事务”,要实现它有若干操作 ——
玩家花费 500 金币购买道具| 性质 | 防止的问题 |
|---|---|
| A | 金币扣了但道具没到账 |
| C | 金币变负数、资产无流水、请求重复执行 |
| I | 两个请求都认为金币足够,发生重复消费 |
| D | 系统返回购买成功,重启后道具消失 |