思路
通过Mybatis的Interceptor拦截执行的SQL语句,判断SQL语句操作的表是否需要进行分库,若需要分库,则根据SQL语句的参数值和分库算法进行分库,分库核心使用Spring的AbstractRoutingDataSource进行数据源的动态切换,同时使用Spring的LazyConnectionDataSourceProxy代理AbstractRoutingDataSource,延迟获取JDBC的Connection对象,否则Mybatis的Interceptor在拦截SQL时,AbstractRoutingDataSource的determineCurrentLookupKey方法已经确定了数据源,也就不能进行切换了。
Mybatis拦截器
Mybatis在执行SQL语句前会产生一个包含SQL语句的Statement对象,并且SQL语句在Statement对象生成之前产生,因此可在Statement生成前拦截到SQL语句。Mybatis的Statement对象是通过RoutingStatementHandler的prepare方法生成的,所以可以拦截StatementHandler的prepare方法获取SQL语句和参数值(RoutingStatementHandler是StatementHandler接口的实现类)。
使用技术
Spring + Mybatis + Mysql + Druid(JDBC连接池),2个Mysql数据库实例
实践步骤
1、数据源配置
1)公共数据源配置
公共数据源配置2)数据源1配置
数据源1配置3)数据源2配置
数据源2配置4)具有路由功能的数据源配置
具有路由功能的数据源配置5)LazyConnectionDataSourceProxy配置
LazyConnectionDataSourceProxy配置LazyConnectionDataSourceProxy代理了AbstractRoutingDataSource。
2、重写AbstractRoutingDataSource的determineCurrentLookupKey方法
定义类ShardingRoutingDataSource,继承AbstractRoutingDataSource,重写determineCurrentLookupKey方法
重写determineCurrentLookupKey方法ShardingContextHolder是通过线程局部变量保存数据源的key值
ShardingContextHolder类源码3、Mybatis的配置
1)定义会话工厂
会话工厂配置dataSource属性引用lazyDataSource,同时配置Mybatis的拦截器。
2)配置事务管理器
事务管理器配置dataSource属性引用lazyDataSource。
3)Mapper接口包扫描配置
Mapper接口包扫描配置4、通过Mybatis的Interceptor拦截SQL语句进行分库
定义一个类,实现Interceptor接口。在intercept方法中拦截执行的SQL语句和参数值,分库逻辑可根据业务需要进行定义。例子中使用表名进行判断。
MybatisSqlInterceptor类源码ShardingDataSourceRouter类,实现数据源key值的动态切换功能。doRoute方法有2个参数,第一个参数是表名,第二个参数是SQL参数的值,可以根据定义不同的分库算法。
ShardingDataSourceRouter类源码doRoute方法中获取所有配置的ShardingDataSourceRule类,ShardingDataSourceRule类是一个抽象类,包含一个表名的属性。doRoute根据表名匹配ShardingDataSourceRule的实现类,ShardingDataSourceRule实现类的doSharding计算数据源的索引值,包含两个参数,第一个是SQL语句的参数值,第二个是数据源的个数。
UserShardingDataSourceRule类的源码UserShardingDataSourceRule类的配置
UserShardingDataSourceRule类配置T_USER是需要进行分库的表名。
基于Mybatis的分库与基于Spring的分库是类似的,一个是基于Mybatis的拦截器插件,一个是基于Spring的AOP的拦截器。
网友评论