13
回答
oracle 多并发写入和读出,如何保证数据的同步性
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   
最近面试遇到问题,设计数据库公司银行账户表,多并发写入和读出,如何保证数据的同步性
举报
左钦菠
发帖于3年前 13回/4K+阅
共有13个答案 最后回答: 3年前

用数据库的transaction。

根据5种情况分别讨论,锁实用的场景 。

更高端的玩法是用rabbitMq或者是ZeroMQ这种队列技术 。

分离业务模型,用最终的结果的同步,来实现超级的高并发。


还有一个技巧,就是如果业务允许,那么不要用取出的数据,经过计算后,覆盖更新原来的数据。而是直接在原有数据上修改,比如update table1 set table1.money=table1.money-100 where table1.user_id='1fd2kdcxz'

而不是这种

update table1 set table1.money=2900 where table1.user_id='1fd2kdcxz'


另外:准备跳槽,求公司收留。。。

--- 共有 1 条评论 ---
左钦菠公司养不起大牛,最近我也在面试 3年前 回复
设计数据库公司银行账户表,多并发写入和读出。

我觉得分两块,悲观锁和乐观锁。
悲观锁则是在数据库层面考虑:一个前面兄长提到过的事务,二个就是SQL的控制
乐观锁则是在代码层面考虑:方法加锁等

我的建议是将整个数据库表设计为只进行insert而不进行update。

然后每天晚上凌晨过后对前一天的插入的收付款进行一次统计过账,形成一个上一日结算。

第二天继续处理业务的时候,就可以直接读昨天的结算来进行处理而不用读所有的明细。


--- 共有 2 条评论 ---
魔力猫回复 @左钦菠 : 绕开也是一种解决办法。没人规定必须硬顶着上呀。 3年前 回复
左钦菠你绕开了问题 3年前 回复

你只要保证同一时间的业务处理唯一性就行了  拿银行账户来说 保证整个服务器集群中同一时间最多只有一个线程对某一个账户进行数据操作    具体你可以搜索一下分布式锁的概念 

数据库层面的事务其实不怎么靠谱

--- 共有 1 条评论 ---
左钦菠嗯,我觉得你说的有点道理,我个人认为感觉会有一种排队的概念在里面 3年前 回复

不要从数据库中读取值,计算后再update,除非这个方法使用了Serializable事务;

Serializable事务可以让N读、N写都只有一个用户在操作,性能非常低下。


--- 共有 1 条评论 ---
左钦菠不明觉历,所以你的解决办法是? 3年前 回复

1)悲观锁 select xxx for update  事务提交或回滚才会释放锁

2)乐观锁 数据版本号 比如hibernate就有乐观锁的实现,你也可以直接实现表里面多加一列版本号每次UPDATE版本号+1如果UPDATE 时发现版本号大于等于现在提交的版本则表示数据不同步

3)DBA调整DB 事务隔离级别 

以上经验全是基于Oracle

一般情况下,1,2 就可以解决数据同步问题了



===这里回复楼主的疑问===

回复 @左钦菠 : 这些都是经过验证做项目的解决方案,关于乐观锁hibernate有自己的实现,如果数据不同步hibernate的处理方式是抛出一个异常,你可以捕获处理  自己实现也是非常非常简单的,无非是加版本号或时间戳解决,乐观锁不存在什么效率问题,因为根本就没锁定什么,他本质就是代码判断提交数据是否过期。


悲观锁的本质是DB提供 明白么?你不锁全表代码合理根本不存在效率问题,我举个例子oracle默认的超时是30s如果一个事务锁定一条数据加了悲观锁,30S内没提交或回滚,后续对该数据的操作会报超时,一个正常的业务操作锁住数据30S,你觉得代码没问题么?


悲观锁,乐观锁,数据库事务隔离级别设置都是提供给你的解决方案,至于效率问题在于人怎么去解决不在于技术

--- 共有 2 条评论 ---
泥沙砖瓦浆木匠回复 @左钦菠 : 你要想想 能把 锁住的压力 转换下。 还有代码乐观考虑使用队列等 3年前 回复
左钦菠首先我不是很赞成你的说法,虽然我不怎么懂数据库,第一你说的锁住就会有效率问题,你说我第二版本控制,那第二个版本低于第一版本难道就要重新做一个操作? 3年前 回复
顶部