分库分表 sharding-jdbc

一、介绍

Sharding-JDBC是一个开源的分布式数据库中间件,它无需额外部署和依赖,旧代码迁移成本几乎为零。Sharding-JDBC作为面向开发的微服务云原生基础类库,完整的实现了分库分表、读写分离和分布式主键功能,
并初步实现了柔性事务。服务云原生基础类库,完整的实现了分库分表、读写分离和分布式主键功能,并初步实现了柔性事务。

官网:http://shardingsphere.io/document/current/cn/overview/

github源码:https://github.com/shardingjdbc/sharding-jdbc 
官方demo:https://github.com/shardingjdbc/sharding-jdbc-example 

二、 为什么选择sharding-jdbc

 目前基础服务有很多业务都涉及到不少数据库拆分的问题,目前行业中比较主流的方式:

    1、代理模式中间件(例如阿里开源的cobar,以及进化版的mycat)
    2、client中间件模式(例如阿里的TDDL,以及我们选择的Sharding-JDBC)
    3、自己业务端查询时动态指定数据源和表信息(spring的动态数据等)


我们为什么会选择Sharding-JDBC呢?
     Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零:   

     可适用于任何基于java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
     可基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid等。
     理论上可支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

    Sharding-JDBC定位为轻量级java框架,使用客户端直连数据库,以jar包形式提供服务,未使用中间层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。采用”半理解”理念的SQL解析引擎,以达到性能与兼容性的最大平衡。
    Sharding-JDBC功能灵活且全面:

          分片策略灵活,可支持=,BETWEEN,IN等多维度分片,也可支持多分片键共用。
          SQL解析功能完善,支持聚合,分组,排序,Limit,TOP等查询,并且支持Binding Table以及笛卡尔积的表查询。
          支持柔性事务(目前仅最大努力送达型)。
          支持读写分离。
          支持分布式生成全局主键。

          Sharding-JDBC配置多样:

          可支持YAML和Spring命名空间配置

          灵活多样的inline方式

三、 使用Sharding-jdbc 我们要关注的几个点

  选择合理的分片键

            需保证数据尽量均匀分配,以免出现热点数据的问题

            需保证大部分查询用到分片键值作为查询条件  以免出现全库扫描的问题

  分库后面临的问题

            事务的取舍

            查询的修改

            数据库链接的浪费

四、  Sharding-jdbc  怎么使用

           采用Java代码配置的方式

           加载多数据,配置分库分表策略

            例如:              

@Configuration
public class ShardingConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    @ConfigurationProperties(ignoreUnknownFields = false, prefix = "datasource.ds0")
    @Bean(name = "ds0")
    public DataSource dataSource0() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @ConfigurationProperties(ignoreUnknownFields = false, prefix = "datasource.ds1")
    @Bean(name = "ds1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean
    @Primary
    public DataSource getDataSource(@Qualifier("ds0") DataSource ds0,
                    @Qualifier("ds1") DataSource ds1) throws SQLException {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());
        shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item");

        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(
                        new StandardShardingStrategyConfiguration("user_id",
                                        new DatabaseShardingAlgorithm()));
        shardingRuleConfig.setDefaultTableShardingStrategyConfig(
                        new StandardShardingStrategyConfiguration("user_id",
                                        new TablePreciseShardingAlgorithm(),
                                        new TableRangeShardingAlgorithm()));

        Map dataSourceMap = new HashMap<>();
        dataSourceMap.put("ds_2017", ds0);
        dataSourceMap.put("ds_2018", ds1);
        Properties properties = new Properties();
        properties.setProperty("sql.show", Boolean.TRUE.toString());


        // RegistryCenterConfiguration regConfig = new RegistryCenterConfiguration();
        // regConfig.setServerLists("localhost:2181");
        // regConfig.setNamespace("orchestration-sharding-data-source");

        // OrchestrationConfiguration orchConfig = new
        // OrchestrationConfiguration("sharding-jdbc-orchestration", regConfig, false);
        // return OrchestrationShardingDataSourceFactory
        // .createDataSource(dataSourceMap, shardingRuleConfig, new ConcurrentHashMap(), new
        // Properties(), orchConfig);
        return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig,
                        new ConcurrentHashMap(), properties);
    }

    @Bean(name = "shardSqlSessionFactory")
    public SqlSessionFactory shardSqlSessionFactory() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(getDataSource(dataSource0(), dataSource1()));
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        bean.setConfiguration(configuration);
        bean.setPlugins(new Interceptor[] {paginationInterceptor()});
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
                        .getResources("classpath:config/mybatis/mapper/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "shardTransactionManager")
    public DataSourceTransactionManager shardTransactionManager() throws Exception {
        return new DataSourceTransactionManager(getDataSource(dataSource0(), dataSource1()));
    }

    @Bean(name = "shardSqlSessionTemplate")
    public JdbcTemplate shardSqlSessionTemplate() throws Exception {
        return new JdbcTemplate(getDataSource(dataSource0(), dataSource1()));
    }

    private static TableRuleConfiguration getOrderTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration();
        result.setLogicTable("t_order");
        result.setActualDataNodes("ds_${2017..2018}.t_order_${[0, 1]}");
        //result.setKeyGeneratorColumnName("order_id");
        result.setDatabaseShardingStrategyConfig(new ComplexShardingStrategyConfiguration("order_id,create_time",
                        new ComplexKeysDataShardingAlgorithm()));
        // result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id",
        // new TablePreciseShardingAlgorithm()));

        return result;
    }

    private static TableRuleConfiguration getOrderItemTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration();
        result.setLogicTable("t_order_item");
        result.setActualDataNodes("ds_${2017..2018}.t_order_item_${[0, 1]}");
        return result;
    }

具体分片策略会根据order表业务的分析  再采用哪种分片方式

 

五、 如何使用

   配置完成以后在业务代码中使用和之前的使用方式没有改变,数据源的路由和表名字的动态修改都是由框架完成。mapper文件,还是像以前一样使用和书写

你可能感兴趣的:(分库分表 sharding-jdbc)