银行为什么不去 UPDATE 余额
一句话总结
银行核心不是修改余额使用,而是积累和汇总交易——因为只要保管余额,当数字不正确时,就没有世界上其他可以对比的对象了。
为什么需要这个?
在一般的服务中处理余额的方法很简单。UPDATE users SET balance = balance - 1000 WHERE id = 7. 一行,快捷,也很方便阅读。
这种方式的问题不是性能,而是无法追溯。有一天,接到余额异常的咨询时,我们手中只有现在的数字一个。要判断这个数字是否正确或错误,必须与在其他地方计算的值进行比较,但没有比较的对象。有人说要翻看日志,但日志有保存期限,格式各不相同,最重要的是不是账簿。
银行早在几个世纪前就解决了这个问题。答案是复式制。
怎么行动
复式会计的规则只有一条。所有交易都记录在两行以上,变数金额的总和和变数金额的总和必须相同。
차변(Debit) 자산이 늘거나, 부채가 줄거나, 비용이 생기는 쪽
대변(Credit) 자산이 줄거나, 부채가 늘거나, 수익이 생기는 쪽
如果顾客存入100万韩元的现金,就会这样记录。
전표 JE-20260825-0001 (입금)
차변 1010 현금 1,000,000
대변 2010 요구불예수금 1,000,000
从银行的角度来看,现金这一资产增加了100万韩元(变动),同时,必须将这笔钱还给客户的义务——存款这一负债增加了100万韩元(代言)。银行存款不是银行的资产,而是负债——这是第一次看银行系统时最容易弄混的地方。
对账单(journal entry)是一笔交易,分行(journal line)是构成对账单的各行。一个对账单上附有三行以上的情况很常见。在支付存款利息时扣除源泉税时,在差变一行上附有两行。
在这个结构中,余额不是存储的值,而是诱导的值。某账户的余额是将该账户所附的所有分销行为合计起来得出的。而且将所有账户合计起来的表格是试算表(trial balance),试算表的差变总和和代变总和必须相同。
这个等式是银行系统拥有的唯一自我验证装置。即使每天有数百万笔交易进来,也可以用一条线条总结下来,问“0人签发”。
现实的核心是由于性能的原因,每个账户都同时持有余额栏。因为每次查询时无法累计数十亿笔。但那个栏是院长的副本,不是原件。如果两者不一致,院长总是获胜。
在现场相遇的样子
第一,**正正是逆分开,而不是UPDATE。**如果发现错误的凭证,不是修改那个凭证,而是把原始凭证像镜子一样倒过来的一张凭证(逆分开)放进去抵消,然后重新登记正确的凭证。原始凭证会剩下三张并排。这看起来很麻烦,但这是两个月后在审计中回答“这个凭证原来是这个金额吗”的人的唯一方法。在原始凭证上有UPDATE的痕迹的系统本身就是审计的注意事项。
进行逆分开时,**金额应按记录的内容填写。**如果将错误的金额原样翻转,错误就会完全抵消。如果说“反正错了,就用正确的金额翻转吧”,那么那一刻的差异就会只抹去一半,剩下的另一半则不会记录在任何地方,而是留在账簿中。
第二,**余额不符的咨询原因通常是这三者中的一个。**原因是会计师计算错误,余额副本错误,或者两者都正确,但看的时间不同。这三者对应完全不同。如果会计师计算错误,必须填写更正单,如果副本错误,会计师重新计算并盖章就可以了,如果时间问题,什么都不改,只说明即可。不告诉对方是哪一个,然后动手是最昂贵的错误。
第三,**只看余额栏的调查必须禁止。**余额一个只是数字。数字本身无法判断是否正确或错误。另一方面,汇总的账目值可以与余额栏进行比较,对账单单位的差额合计本身可以进行验证。调查时,打开哪个表格先决定当天几点下班。
将元长放在数据库中的规则
将复式部记转为表格的方法有很多种,但后面不会后悔的形式基本上是 一样。
**分歧在一个交易中有两行以上,和为0。**将变量和对应变量放在不同的表格中或 如果在一行中输入两个金额,总有一天只会输入一边。**在同一表格中输入多行, 让数据库确认那个组的和是否为0。
create table entries(
id bigserial primary key,
txn_id uuid not null,
account_id bigint not null references accounts(id),
amount_minor bigint not null, -- 차변은 양수, 대변은 음수
currency char(3) not null,
posted_at timestamptz not null,
business_date date not null);
create index on entries(txn_id);
-- 묶음의 합이 0이 아니면 커밋을 막는다(지연 제약 또는 트리거로).
既不更新也不删除。错误输入的留言不是要删除,而是反对 再放一个分叉来抵消,把两个束子互相连接。这样才能“在某个时候 余额是多少”总是可以回答的。
**余额存起来,但用结算方式验证。**每次加起来都很慢,所以单独存余额。 虽然会一直拿着,但那个价格和分开的合计一定会有不一致的瞬间。在一定时间点的 以快照+之后的愤怒的形式留下来,在夜间再加上整个内容进行对比。
**金额是最小单位的整数。**韩元是1,美元是分。不使用小数点。 如果打了多次电话,绝对不会把金额和电话分开——把电话中的两个金额 如果有增加的代码,那就是错误。
**将工作日期和开盘时间分开。**凌晨1点入场的交易属于前一天营业日。 可以。如果捆成一团的话,截止日期的数字因人而异。
**同时性以账户为单位计算。**如果同时在同一账户上记入,余额就会不一致。
账户行select ... for update或将其归类,或将余额完全视为分开的合计。
选择不设置余额行的设计。
下次实习要做的事情
亲自制作三天账簿的快照,在其中找到隐藏的1个车代不一致。从实算表开始,缩小到一张全表,甚至到分开行的一行,通过余额栏和账簿合算,确认两者的性质为什么不同。最后,不动账簿,直接用逆分开和再起表纠正。