Java面试10|数据库相关
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java面试10|数据库相关相关的知识,希望对你有一定的参考价值。
1、ID分配单点问题
系统使用一张表的自增来得到订单号,所有的订单生成必须先在这里insert一条数据,得到订单号。分库后,库的数量变多,相应的故障次数变多,但由于单点的存在,故障影响范围并未相应的减少,使得全年downtime上升,可用性下降。
针对ID分配单点问题,考虑到数据库表分配性能的不足,调研了Tair、Redis、Snowflake等ID分配器,同时也考虑过将ID区间分段,多点分配。
但最后没有使用这些方案,主要原因是ID分配对系统而言是强依赖服务,在分布式系统中,增加这样一个服务,整体可用性必然下降。 我们还是从数据库入手,进行改良,方案如下。
如下图,由原来一个表分配改为100张表同时分配,业务逻辑上根据不同的表名执行一个简单的运算得到最终的订单号。
ID与用户绑定:对订单系统而言,每个用户有一个唯一的userid,我们可以根据这个userid的末2位去对应的id_x表取订单号,例如userid为10086的用户去id_86表取到值为42,那订单号就42*100+86=4286。
将订单内容根据userid模100分表后如下图:
通过看上面的技巧,我们发现订单根据“userid取模”分表和根据“订单号取模”来分表结果是一样的,因为后两位数一样。到此,分库操作就相当简单容易了,极限情况下分成100个库,每个库两个表。同一个用户的请求一定在同一个库完成操作,达到了完全拆分。
注:一般情况下,订单数据分表都是按userid进行的,因为我们希望同一个用户的数据存储在一张表中,便于查询。当给定一个订单号的时候,我们无法判别这个订单在哪个分表,所以大多数订单系统同时维护了一个订单号和userid的关联关系,先根据订单号查到userid,再根据userid确定分表进而查询得到内容。在这里,我们通过前面的技巧发现,订单号末二位和userid一样,给定订单号后,我们就直接知道了分表位置,不需要维护关联表了。给定订单号的情况下,单次查询由原来2条SQL变为1条,查询量减少50%,极大提升了系统高并发下性能。
一般生成的唯一ID最好有一些意义,如:
时间戳+用户标识码+随机数
则时间戳可以排序,用户标识码可以拿来进行分表的表定位,生成还比较简单
也可以采用应用层主键方案,这样就可以进行数据库切分,资源定位等。
看一下如何生成全局唯一ID,参考:
(1)http://www.cnblogs.com/baiwa/p/5318432.html
(2)http://blog.csdn.net/houkai6/article/details/17713845
2、
3、数据库如何实现事务?
4、数据库与缓存不一致问题
DB与Cache缓存不一致问题解决办法:
(1)"两次淘汰法" 在增加数据时添加到数据库同时向缓存中插入一条记录。更新时,可以采用先淘汰缓存,后写入数据,然后再淘汰一次缓存的策略,也可以更新数据库后更新缓存,从而不会导致缓存未命中的问题。
(2)添加数据时先在数据库中插入,然后再在缓存中保存一份。频繁更新数据时可先更新缓存,如更新Redis时需要记录更新的key值,然后异步刷新到数据库中。
参考:
(1)redis与DB数据同步问题 http://blog.csdn.net/seapeak007/article/details/53410553
(2)缓存架构设计细节二三事 http://www.jianshu.com/p/a38b26b55696
(3)主从DB与Cache一致性 http://www.jianshu.com/p/e3f5ff55f0fd
以上是关于Java面试10|数据库相关的主要内容,如果未能解决你的问题,请参考以下文章