电商的账户系统

账户系统负责记录和管理用户账户的余额,这个余额可能受到用户充值或者退款等途径的

对于一个账户系统,包含的数据模型基本如下

图片

包含了用户ID,账户余额,更新时间就可以了

对于账户系统,需要和其他有着密切的关联,至少和财务,订单,交易等系统有关联,账户系统内的数据至少可以自洽,至少所有用户的余额加起来,可以等于这个电商公司账户的总余额,而且可以和财务系统的数据对得上,而且为了可以对上账,往往一个电商系统会有一个对账系统,来矫正不同系统间的数据差异

所以,对不上账是我们需要面对的问题,而对不上账本质上就是冗余数据的一致性,这个冗余的数据,是在不同系统中记录的相同信息的数据,这种记录浪费了存储空间,而且不易保证其的一致性

但是如果不进行不一致性的保存,那么在交易之前,通过所有历史交易记录算一下余额,会导致降低其速度,性能满足不了交易的需求,所以会在账户中保存其当前余额,用存储空间换时间的设计

而且,我们还会保存一个流水系统,保存其所有的流水账,这个流水账系统,需要我们保证其只能新增,不可以修改或者删除,即时一个交易需要取消,也是记录一笔取消交易的流水,而不是删除交易流水

对账时候,也是以流水为准修正余额数据,保证后续能对得上帐

对于冗余数据的更新

我们保证记录流水和更新余额两个操作,要么都成功,要么都失败,不能有任何一笔交易出现,记录了流水但是没有更新余额

这就是事务机制

对于事务机制的使用,本质上很简单,在mysql中按照如下操作就可以了

mysql> begin;  — 开始事务

Query OK, 0 rows affected (0.00 sec)

mysql> insert into account_log …;  — 写入交易流水

Query OK, 1 rows affected (0.01 sec)

mysql> update account_balance …;  — 更新账户余额

Query OK, 1 rows affected (0.00 sec)

mysql> commit; # 提交事务

Query OK, 0 rows affected (0.01 sec)

简单来说,只需要在开始前标记一个begin,然后执行后提交commit就可以了

这就可以保证两个操作在一个事务中执行了,这就是事务的原子性

而且在事务执行的过程中,正常的查询不会查询到事务的中间状态,只有事务结束后可以看到事务的修改,这就是一致性

而且每个事务在执行的过程中,中间的状态对于其他事务是不可见的,在事务A中,写入操作时候,其他事务是读取不到的,这就是事务的隔离性

只要事务提交成功,就会被持久化到磁盘,这就是持久性

然后是事务的隔离级别

不同的事务隔离级别不同

图片

四种隔离级别RU RC RR SE,越来越重

RU级别没完全不隔离,事务中间状态可见

序列化则是太强,所以也不用

对于RC和RR两种

MySQL默认RR,可以避免脏读

两者唯一的区别在于,可重复读

就是在一个事务的过程中,能不能读到其他的事务修改后的数据

如果能读到变化,就是不可重复读,否则就是可重复读

那么在账户余额表中,整体的流程如下

我们先给账户余额表增加一个log_id属性,记录最后一笔交易的流水号

然后开启事务,查询并记录当前账户的曰和最后一笔交易的流水号

然后写入流水记录

然后更新账户余额,在更新的时候,指定流水号

然后检测余额的返回值,更新成功就提交事务

对于流水表和余额表的建表语句

基本如下

CREATE TABLE `account_log` (

`log_id` int NOT NULL AUTO_INCREMENT COMMENT ‘流水号’,

`amount` int NOT NULL COMMENT ‘交易金额’,

`timestamp` datetime NOT NULL COMMENT ‘时间戳’,

`from_system` int NOT NULL COMMENT ‘转出系统编码’,

`from_system_transaction_number` int DEFAULT NULL COMMENT ‘转出系统的交易号’,

`from_account` int DEFAULT NULL COMMENT ‘转出账户’,

`to_system` int NOT NULL COMMENT ‘转入系统编码’,

`to_system_transaction_number` int DEFAULT NULL COMMENT ‘转入系统的交易号’,

`to_account` int DEFAULT NULL COMMENT ‘转入账户’,

`transaction_type` int NOT NULL COMMENT ‘交易类型编码’,

PRIMARY KEY (`log_id`)

);

CREATE TABLE `account_balance` (

`user_id` int NOT NULL COMMENT ‘用户ID’,

`balance` int NOT NULL COMMENT ‘余额’,

`timestamp` datetime NOT NULL COMMENT ‘时间戳’,

`log_id` int NOT NULL COMMENT ‘最后一笔交易的流水号’,

PRIMARY KEY (`user_id`)

);

账户系统可以记录每个用户的余额,但是还需要记录账户的流水,流水是只能增加,任何情况下都不能修改和删除,每次交易的时候都需要将流水和余额放在一个事务中更新

事务具有原子性 一致性 隔离性 持久性 四种特性,也就是ACID,可以保证一个事务中更新要么都成功,奥秘都失败

发表评论

邮箱地址不会被公开。 必填项已用*标注