由于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; } }