sharding-jdbc多数据源配置分库分表

由于sharding-jdbc对sql有多种语法限制,如果用同一个数据源,不分表的sql语句也无法规避限制

因此可以使用多数据源方式解决该问题。

1指定mapper注解java接口所在的目录

basePackages = "com.order.mapper.second"

2指定mapper sql语句xml所在的目录

String MAPPER_LOCATION = "classpath:mapper/second/*.xml"
package com.order.config;

import com.order.dao.RangeShardingTableStrategy;
import com.order.dao.ShardingTableStrategy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.shardingsphere.spring.boot.util.DataSourceUtil;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@Configuration
@MapperScan(basePackages = "com.order.mapper.second", sqlSessionFactoryRef = "secondSqlSessionFactory")
public class SecondDataSourceConfig {

    // 精确到目录,以便跟其他数据源隔离
    static final String MAPPER_LOCATION = "classpath:mapper/second/*.xml";
    @Value("${spring.shardingsphere.datasource.order.jdbc-url}")
    private String url;
    @Value("${spring.shardingsphere.datasource.order.username}")
    private String username;
    @Value("${spring.shardingsphere.datasource.order.password}")
    private String password;

    /**
     * 创建sharding-jdbc的DataSource实例
     *
     * @return
     */
    @Bean(name = "secondDataSource")
    @Qualifier("secondDataSource")
    public DataSource shardingDataSource() {
        //return DataSourceBuilder.create().build();
        return getShardingDataSource();
    }

    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("secondDataSource") DataSource clusterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(clusterDataSource);
        sessionFactory.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources(SecondDataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }


    DataSource getShardingDataSource() {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        shardingRuleConfig.getBindingTableGroups().add("order_all");
        //shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", new ShardingTableStrategy()));
        shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", new ShardingTableStrategy(),new RangeShardingTableStrategy()));
        try {
            return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new Properties());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
        KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE", "order_id");
        return result;
    }

    TableRuleConfiguration getOrderTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration("order_all", "order.order_all_${0..15}");
        //result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
        return result;
    }

    @ConfigurationProperties(prefix = "spring.shardingsphere.datasource.order")
    Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> result = new HashMap<>();
        // 配置真实数据源
        Map<String, Object> dataSourceProperties = new HashMap<>();
        dataSourceProperties.put("DriverClassName", "com.mysql.jdbc.Driver");
        dataSourceProperties.put("jdbcUrl", url);
        dataSourceProperties.put("username", username);
        dataSourceProperties.put("password", password);
        try {
            DataSource ds = DataSourceUtil.getDataSource("com.zaxxer.hikari.HikariDataSource", dataSourceProperties);
            result.put("order", ds);
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
        return result;
    }
}

 为了便于查询,需要设置分表策略,范围查询策略

shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", new ShardingTableStrategy(),new RangeShardingTableStrategy()))

这里面2个自定义类如下

ShardingTableStrategy
public class ShardingTableStrategy implements PreciseShardingAlgorithm<String> {

    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {

        for (String tableName : collection) {
            long divide = Math.abs(preciseShardingValue.getValue().hashCode()) % 16;
            if (tableName.endsWith("" + divide)) {
                return tableName;
            }
        }
        throw new IllegalArgumentException();
    }
}
RangeShardingTableStrategy
public class RangeShardingTableStrategy implements RangeShardingAlgorithm<String> {


    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
        Collection<String> collect = new ArrayList<>();
        for (int i = 0; i < 16; i++) {
            for (String each : collection) {
                if (each.endsWith(i % collection.size() + "")) {
                    collect.add(each);
                }
            }
        }
        return collect;
    }
}