一种简单的分库分表代码写法

分库分表本质上是持有很多库构成的Map,通过分库分表算法算出路由的库,然后对这个库进行访问,本方法用到的知识点概览:

  • 通过Adapter模式实现jdbc的DataSource接口,透明访问多库
  • 通过templateMethod模式实现具体的路由
  • 通过threadlocal跨线程访问做桥,DAO把分库号传递给threadlocal,分库访问直接取threadlocal中的分库号。

Spring本身提供了支持分库分表的基类,org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,我们可以继承本类,AbstractRoutingDataSource持有一个Map数据源,暴露了determineCurrentLookupKey方法,方法返回的Key就是本次分库对应Map的key对应的数据源。我们的子类只要实现determineCurrentLookupKey方法就可以。

 

一种简单的分库分表代码写法_第1张图片

    
    
        
            
                
                
                
                
                
            
        
        
    

PS:既然Map的key可以做分库,包括读写分离,只不过多拼接个前缀而已。

DynamicDataSource的determineCurrentLookupKey直接通过DataSourceLookupKeyStrategy持有threadlocal变量为桥,直接得到threadlocal中持有的分库号,代码如下:

@Setter
public class DynamicDataSource extends AbstractRoutingDataSource {
    private DataSourceLookupKeyStrategy dataSourceStrategy;

    @Override
    protected Object determineCurrentLookupKey() {
        //根据配置信息动态切换获取数据源Key策略
        return this.dataSourceStrategy.lookupCurrentDataSourceKey();
    }
}

DAO也持有DataSourceLookupKeyStrategy这个桥,把分库分表字段传递给DataSourceLookupKeyStrategy,DataSourceLookupKeyStrategy来进行分库分表算法,并把分库结果传递threadlocal这个桥,分表则需要自己传递给sql拼接。

比如查询分库分表的用户:

   

    private SqlMapClientTemplate mysqlTemplate;
    private DataSourceLookupKeyStrategy dataSourceLookupKeyStrategy;
    public User getUserByUserName(String userName) {
        //1.设置数据源,并获取表的下标
        Integer tableNum = dataSourceLookupKeyStrategy.setDbIndexAndReturnTableIndex(userName);

        //2.构造mybatis查询的参数
        Map paramMap = new HashMap();
        paramMap.put("username", "username");
        paramMap.put("tableNum", tableNum);//设置分表后缀

        //3.执行查询语句 select * from user_$tableRouteNo$ where name=#name#
        return mysqlTemplate.queryForList("user.getUserByUserName", paramMap);
    }

桥+分库分表的示例代码如下

public class DataSourceLookupKeyStrategy {
    //分库key桥,存储当前数据库的标识
    private static final ThreadLocal dbNumThreadLocal = new ThreadLocal();

    //分库分表路由算法委托出去
    @Setter
    private DbRouteService routeService;

    /**
     * 在DAO中使用,根据分库分表字段计算分库序号,并设置到ThreadLocal中,并返回分表字段
     * @param routeValue 分库分表字段
     * @return 表序号,在DAO中设置到ibatis上下文中
     */
    public Integer setDbRouteReturnTableNo(String routeValue) {
        dbNumThreadLocal.remove();
        // 分库算法,此处直接常量品拼接用户库+访问主库+分库号,实际项目中替换成真实代码就可以
        String dbNoKey = "user_" + "master_" + routeService.getDbIndex(routeValue);
        // 设置库路由,包括分机房
        dbNumThreadLocal.set(dbNoKey);
        return routeService.getTableIndex(routeValue);
    }
    /**
     * 得到当前数据库的标识
     * 被动态数据源使用,和动态数据源持有的标识相对应
     *
     * @return 当前数据库的标识
     */
    public String lookupCurrentDataSourceKey() {
        return dbNumThreadLocal.get();
    }
}

 

你可能感兴趣的:(互联网)