思路
通過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配置
3)數據源2配置
4)具有路由功能的數據源配置
5)LazyConnectionDataSourceProxy配置
LazyConnectionDataSourceProxy代理了AbstractRoutingDataSource。
2、重寫AbstractRoutingDataSource的determineCurrentLookupKey方法
定義類ShardingRoutingDataSource,繼承AbstractRoutingDataSource,重寫determineCurrentLookupKey方法
ShardingContextHolder是通過線程局部變量保存數據源的key值
3、Mybatis的配置
1)定義會話工廠
dataSource屬性引用lazyDataSource,同時配置Mybatis的攔截器。
2)配置事務管理器
dataSource屬性引用lazyDataSource。
3)Mapper接口包掃描配置
4、通過Mybatis的Interceptor攔截SQL語句進行分庫
定義一個類,實現Interceptor接口。在intercept方法中攔截執行的SQL語句和參數值,分庫邏輯可根據業務需要進行定義。例子中使用表名進行判斷。
ShardingDataSourceRouter類,實現數據源key值的動態切換功能。doRoute方法有2個參數,第一個參數是表名,第二個參數是SQL參數的值,可以根據定義不同的分庫算法。
doRoute方法中獲取所有配置的ShardingDataSourceRule類,ShardingDataSourceRule類是一個抽象類,包含一個表名的屬性。doRoute根據表名匹配ShardingDataSourceRule的實現類,ShardingDataSourceRule實現類的doSharding計算數據源的索引值,包含兩個參數,第一個是SQL語句的參數值,第二個是數據源的個數。
UserShardingDataSourceRule類的配置
T_USER是需要進行分庫的表名。
基于Mybatis的分庫與基于Spring的分庫是類似的,一個是基于Mybatis的攔截器插件,一個是基于Spring的AOP的攔截器。