如何快速实现分库分表?
Posted 码农搬砖日记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何快速实现分库分表?相关的知识,希望对你有一定的参考价值。
小明在外包公司负责一个项目一段时间了,这个项目还算不错,一段时间后就积累了一定的数据量。有一天领导找到小明说:“现在这个项目数据量上来了,单库逐渐有点抗不住了,现在客户砸钱了,要求提升性能,你尽最快的能力对我们这个项目进行分库分表吧。怎么实现我不管,要尽快上线”
小明听到后有点蒙圈了,分库分表这事情我还没干过啊,听起来技术含量很高。小明只能回到座位后,使出程序员的杀手锏:百度,搜寻解决方案。
这一搜,有很多解决方案,譬如shading-sphere、mycat...等等,但是小明有点惆怅。刚毕业不久,接触的东西也还不多,只懂最简单最流行的单体web应用的框架SSM(springmvc、spring、Mybatis)。这些第三方的中间件虽然可以解决问题,但是引入这些中间件成本太高了,时间有限,资金也不到位,最好就在现有的框架下能实现这个需求。
通过一番努力,小明在某论坛上和大神交流,得到了一种最直接的解决方案。通过spring来实现,spring果然不愧是java开发的代名词,功能太强大了,连分库分表都能兼顾。怎么做呢?
Spring提供了数据源动态切换的接口AbstractRoutingDataSource,其类图如下。
这时候我们需要在spring的环境下配置多个数据源,关键就在于Spring如何帮我们切换不同的数据源了,我们需要实现AbstractRoutingDataSource,并覆盖其方法:
分库
那么如何实现此方法呢?一般来说,我们分库分表都会根据一个分片键来计算分片值,那么我们可以根据dao或service的入参来计算分片键。小明想了一个办法,通过AOP拦截dao或service方法,通过调用相应的策略类来对参数进行计算,并把计算好的分片值放到线程变量ThreadLocal中,然后在上面提到的AbstractRoutingDataSource#determineCurrentLookUpKey中取出线程变量并返回,让spring路由到指定的数据源。
拦截器如下:
方法实现大致如下(StrategyHolder实际上就是一个线程变量的包装):
分库搞定好,小明还不能放松下来,因为spring虽然提供了动态数据源的切换,但是并没有提供数据表的切换啊。但是能不能利用类似的思路完成呢?于是小明死磕了几天Mybatis源码,终于找到了解决方案。
2.分表
小明依旧利用了AOP和线程变量,数据表的切换深入到了Mybatis的源码,小明使用了Mybatis插件的方式。依旧是通过在方法前添加AOP注解,并且计算好分片值后放到线程变量中。那么如何通过分片值路由到正确的表呢?小明在mybatis的mapper.xml中做了手脚,用占位符代表具体的表名
然后通过mybatis插件和线程变量修改sql里这个占位符,小明的mybatis插件拦截了mybatis的StametHandler的prepare方法(Mybatis和插件的相关知识就不在这里讲解了)。其实现方法如下:
第一步先通过sqlConverter对select *from $[id_depttable]$...的占位符进行替换,得到最后mysql可执行的targetSql,并且通过ReflectionUtils的方法替换原来的带占位符的sql,从而最终路由到正确的表。
以上小明只是写了个demo,并把解决方案告诉了他的老大,老大觉得很满意,虽然这个方案仍然有些缺陷(譬如只支持单库事务等等...),但是外包项目,钱给不到位就是这样的啦。但是老大也展开了瞎想,觉得自己手里有挺多项目,希望有个地方可以统一管理这些数据源,不知道小明可不可以做到...
小明挠着头说可以是可以,以后加薪升职再来干吧。
对了,小明还给这个项目起了个很酷的名字:Asgard(完)
以上是关于如何快速实现分库分表?的主要内容,如果未能解决你的问题,请参考以下文章