• 金融业务系统中的数据库事务:01. 五类问题


    众所周知,金融业是一个直接和钱打交道的行业。通俗的讲,金融公司提供的是中介服务,并从中收取中介费,盈利模式是“本金”——“收益”。而实体经济的盈利模式是“本金”—“产品”—“收益”。所以,在金融业中对金额是非常敏感的,下面以“取款”、“转账”和“查询余额”等银行业务为例来说明,如何通过数据库事务保证该类业务正确,完整和安全的进行。

    一. 数据库事务简介

    数据库事务(Transaction)是指:作为单个逻辑工作单元执行的一些列操作。事务内的操作要么全部执行,要么全部不执行,回到初始状态。事务必须具备下面四点属性(ACID)

    1. 原子性(Atomic):事务内的操作必须是全部执行,或者全部不执行,回滚到初始状态。

    2. 一致性(Consistent):事务在完成后,数据库内的数据是一致的,没有脏数据产生。

    3. 隔离性(Isolation):事务在并发执行时,事务之间的修改必须是隔离的,好比事务是串行执行的一样。

    4. 持久性(Duration):事务完成后,对数据的修改是持久的。

    这是个人理解的数据库事务,详细的定义和介绍可以参照维基百科。

    二. 数据库并发问题

    同一时间可能存在多个用户访问数据库,并做相应的操作。必然就会存在数据库中同一份数据被多个事务同时访问,如果处理不好,总体来说会引入五类问题:3类读问题(脏读、不可重复读和幻读)和2类写问题(第一类丢失更新和第二类丢失更新)。下面以“取款”、“转账”和“查询余额”三类业务来解释出现这五类问题的场景:

    1. 脏读(Dirty Read)

    举一个生活中的例子,结巴A来到超市买东西,老板B问他:“抽中华烟吗?”。顾客A说“我…抽…抽…抽”,老板B忙给他拿了包烟过来,这时结巴A终于憋出了后半句“抽不起啊”。在这个生活场景中,老板B对结巴A进行了脏读。

    脏读的现象是:事务B读取了事务A没有提交的更改数据,并做了相应的操作。此时,事务A回滚,那么事务B基于之前数据的操作都是错误的。来看看转账和取款的例子:

    时间 取款事务A 转账事务B
    T1 开始事务  
    T2   开始事务
    T3   余额1000元,转出100元,余额改为900元
    T4 余额900元(脏读)  
    T5   撤销事务
    T6 取款100元,余额改为800元  
    T7 提交事务  

    从上述例子中可以看出,脏读导致账户损失了100元。

    2. 不可重复读(Unrepeatable Read)

    还是刚才生活中的例子,A问B:“还有中华烟吗?”,B说:“还有一包,要吗?”,A思索了一下,此时B又去招待其他顾客了,而且将烟卖给了另一个顾客。等A想好,并等B忙完后说“给我来一包吧”,B说:“买完了”,然后两人开始吵架了。在这个场景中,在A身上就发生了不可重复读问题。

    不可重复读现象是:事务A在事务B提交某条更新数据的前后,对该条数据访问时,会产生不一致的情况。来看看,查询和转账业务

    时间 取款事务A 转账事务B
    T1   开始事务
    T2 开始事务  
    T3   余额1000元
    T4 查询余额1000元  
    T5   转出100元,余额改为900元
    T6   提交事务
    T7 查询余额900元  
    T8 提交事务  

    从上面例子中可以看出,在同一事务A中,T4和T7查询的结果不一致。

    3. 幻读(Phantom Read)

    还是刚才生活中的例子,A问B:“店里有多少中华烟?”,B说:“还有2包,都要么?”,这时A在思索一下。恰巧,这时另一个顾客C退了一包回来。等A想好后说:“我都要了”,其实此时店里一共还有三包烟了。在这个场景中,在A身上发生了幻读的情况。

    幻读的现象是:事务A在事务B插入某条数据的前后,对数据记录进行统计时,读取到事务B新插入的一条记录。幻读容易与不可重复读混淆,幻读指的是读取了新插入的数据,不可重复读指的是读取了新更新(修改,删除)的数据。在数据库中,防止这两类问题所采取的策略是不同的,不可重复读采取行级锁防止更新,而幻读需要采取表级锁防止插入。来看看“统计账户总额”和“开户”业务

    时间 统计账户总额事务A 开户事务B
    T1 开始事务  
    T2   开始事务
    T3 查询总额为1000元  
    T4   新增一个账户,并存款100元
    T5   提交事务
    T6 查询总额为1100元  
    T7 提交事务  

    从上面例子中可以看出,在同一事务A中,T3和T6统计的结果不一致。

    4. 第一类丢失更新(Lost Update)

    还是刚才生活中的例子,不过角色要丰富一下,顾客变成2个:A1和A2,老板变成2个:B1和B2。场景是这样的,A1问B1:“还有多少中华烟”,B1清点了一下说:“还有2包”。A2问了B2同样的问题,B2也回答说是“还有2包”,然后A2买了1包。但是B2并没有告知B1。后来,A1也要了一包烟,不一样的事,不久A1又把烟给退了,可是B1还以为店里有2包烟。在这个场景中,B1身上发生了第一类更新问题。

    第一类更新问题指的是:事务A撤销时,导致事务B已提交的修改被覆盖。来看看取款和转账业务:

    时间 取款事务A 转账事务B
    T1 事务开始  
    T2   事务开始
    T3 查询余额1000元  
    T4   查询余额1000元,并转入100元余额1100元
    T5   提交事务
    T6 取出100元,余额900元  
    T7 撤销事务  
    T8 余额恢复为1000元  

    从上面例子中可以看出,事务A撤销后,导致事务B已提交的修改被覆盖

    5. 第二类丢失更新(Second Lost Update)

    和第一类丢失更新不同的是,第二类丢失更新指的是:事务A提交的结果,将事务B提交的结果覆盖了。仍然以上面的取款和转账业务为例:

    时间 取款事务A 转账事务B
    T1 事务开始  
    T2   事务开始
    T3 查询余额1000元  
    T4   查询余额1000元,并转入100元余额1100元
    T5   提交事务
    T6 取出100元,余额900元  
    T7 提交事务  
    T8 余额为900元  

    从上面例子中可以看出,事务A提交后,导致事务B已提交的修改被覆盖。

  • 相关阅读:
    在jQuery ajax中按钮button和submit的区别分析
    jQuery学习-打字游戏
    AndroidManifest.xml权限大全
    判断数据连接----小程序
    ADB常用的几个命令
    Android的ADB配置环境和adb指令使用
    读懂Android项目结构目录
    Android四大组件
    多态继承
    匿名内部类
  • 原文地址:https://www.cnblogs.com/zhouwei0213/p/2991065.html
Copyright © 2020-2023  润新知