编程语言
首页 > 编程语言> > 【ShardingSphere技术专题】「ShardingJDBC」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)

【ShardingSphere技术专题】「ShardingJDBC」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)

作者:互联网

前提介绍

ShardingSphere介绍

ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。

shardingJDBC使用的范围

详细一点的介绍直接看官网:https://shardingsphere.apache.org/document/current/cn/overview/

SQL语句相关

数据分片相关

SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。

目前提供4种分片算法

分片策略:包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。

目前提供5种分片策略

配置相关

分片规则:分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等。


开发步骤

开发整合方式

方式一:基于配置文件集成,方便简单但是不够灵活

	<!--主要有以下依赖,分库分表策略直接在application.properties做相关配置即可-->
	<dependency>
		<groupId>io.shardingsphere</groupId>
		<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
		<version>3.1.0.M1</version>
	</dependency>
	<dependency>
		<groupId>io.shardingsphere</groupId>
		<artifactId>sharding-jdbc-spring-namespace</artifactId>
		<version>3.1.0.M1</version>
	</dependency>

方式二:这里我们主要基于java config的方式来集成到springboot中,更适合学习和理解

//相关依赖
<dependency>
	<groupId>io.shardingsphere</groupId>
	<artifactId>sharding-jdbc-core</artifactId>
	<version>3.1.0</version>
</dependency>
<!--<dependency>
	<groupId>io.shardingsphere</groupId>
	<artifactId>sharding-transaction-2pc-xa</artifactId>
	<version>3.1.0</version>
</dependency>-->
<dependency>
	<groupId>io.shardingsphere</groupId>
	<artifactId>sharding-jdbc-orchestration</artifactId>
	<version>3.1.0</version>
</dependency>
<dependency>
	<groupId>io.shardingsphere</groupId>
	<artifactId>sharding-orchestration-reg-zookeeper-curator</artifactId>
	<version>3.1.0</version>
</dependency>

定义相关配置类(DataSourceConfig => MybatisConfig => TransactionConfig)

ShardingSphereDataSourceConfig
import javax.sql.DataSource;
import java.lang.management.ManagementFactory;
import java.sql.SQLException;
import java.util.*;

/**
 * @Author zhangboqing
 * @Date 2020/4/25
 */
@Configuration
@Slf4j
public class ShardingSphereDataSourceConfig {

    @Bean("shardingDataSource")
    DataSource getShardingDataSource() throws SQLException {
        //初始化相关的分片规则配置信息控制机制
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        // 设置相关的数据源
        shardingRuleConfig.setDefaultDataSourceName("ds0");
       // 设置相关的Order表的相关的规则信息配置机制
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
       // 设置相关的OrderItem表的相关的规则信息配置机制
        shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());
        // 配置绑定表关系
        shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item");
        // 广播表操作机制
        shardingRuleConfig.getBroadcastTables().add("t_config");
        // 设置相关的分片机制策略(数据源分片策略机制控制)
        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));
        // 设置相关的分片策略机制,子啊inline模式下(包含了两种模式)
        shardingRuleConfig.setDefaultTableShardingStrategyConfig(getShardingStrategyConfiguration());
        // ShardingPropertiesConstant相关配置选项
        Properties properties = new Properties();
        //是否打印SQL解析和改写日志
        properties.put("sql.show",true);
       //用于SQL执行的工作线程数量,为零则表示无限制
        propertie.setProperty("executor.size","4");
       //每个物理数据库为每次查询分配的最大连接数量
        propertie.setProperty("max.connections.size.per.query","1");
       //是否在启动时检查分表元数据一致性
        propertie.setProperty("check.table.metadata.enabled","false");
		//用户自定义属性
        Map<String, Object> configMap = new HashMap<>();
        configMap.put("effect","分库分表");
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, properties);
    }

    // 配置相关的分片策略机制
    private ShardingStrategyConfiguration getShardingStrategyConfiguration(){
        // 精确匹配
        PreciseShardingAlgorithm<Long> preciseShardingAlgorithm = new PreciseShardingAlgorithm<Long>() {
            @Override
            public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
                String prefix = shardingValue.getLogicTableName(); //逻辑表名称
                Long orderId = shardingValue.getValue(); //订单编码
                long index = orderId % 2; //订单表(分表路由索引)
                // t_order + "" + 0 = t_order0
                String tableName = prefix + "" +index;
                // 精确查询、更新之类的,可以返回不存在表,进而给前端抛出异常和警告。
                if (availableTargetNames.contains(tableName) == false) {
                    LogUtils.error(log,"PreciseSharding","orderId:{},不存在对应的数据库表{}!", orderId, tableName);
                    return availableTargetNames.iterator().next();
                }
                return tableName;
//                return availableTargetNames.iterator().next();
            }
        };
        // 范围匹配
        RangeShardingAlgorithm<Long> rangeShardingAlgorithm = new RangeShardingAlgorithm<Long>() {
            @Override
            public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
                String prefix = shardingValue.getLogicTableName();
                Collection<String> resList = new ArrayList<>();
                // 获取相关的数据值范围
                Range<Long> valueRange = shardingValue.getValueRange();
                // 如果没有上限或者下限的没有,则直接返回所有的数据表
                if (!valueRange.hasLowerBound() || !valueRange.hasUpperBound()) {
                    return availableTargetNames;
                }
               // 获取下限数据范围
                long lower = shardingValue.getValueRange().lowerEndpoint();
                BoundType lowerBoundType = shardingValue.getValueRange().lowerBoundType();
               // 获取下限数据范围
                long upper = shardingValue.getValueRange().upperEndpoint();
                BoundType upperBoundType = shardingValue.getValueRange().upperBoundType();
               // 下限数据信息值
                long startValue = lower;
                long endValue = upper;
               // 是否属于开区间(下限)
                if (lowerBoundType.equals(BoundType.OPEN)) {
                    startValue++; //缩减范围1
                }
               // 是否属于开区间(上限)
                if (upperBoundType.equals(BoundType.OPEN)) {
                    endValue--; // 缩减范围1
                }
               // 进行计算相关所需要是实体表
                for (long i = startValue; i <= endValue ; i++) {
                    long index = i % 2;
                    String res = prefix + "" +index;
                    // 精确查询、更新之类的,可以返回不存在表,进而给前端抛出异常和警告。
                    if (availableTargetNames.contains(res) == false) {
                        LogUtils.error(log,"RangeSharding","orderId:{},不存在对应的数据库表{}!", i, res);
                    }else{
                       resList.add(res);
                   }
                }
                if (resList.size() == 0) {
                    LogUtils.error(log,"RangeSharding","无法获取对应表,因此将对全表进行查询!orderId范围为:{}到{}",startValue,endValue);
                    return availableTargetNames;
                }
                return resList;
            }
        };

        // 设置相关整体的算法整合
        ShardingStrategyConfiguration strategyConf = new StandardShardingStrategyConfiguration("order_id", preciseShardingAlgorithm, rangeShardingAlgorithm);
        return strategyConf;
    }

    // 获取相关的Order订单规则表配置信息控制配置控制机制
    TableRuleConfiguration getOrderTableRuleConfiguration() {
        // 逻辑表 + 实际节点 :设置逻辑表与数据节点(数据分片的最小单位)的映射关系机制
        TableRuleConfiguration result = new TableRuleConfiguration("t_order", "ds${0..1}.t_order${0..1}");
        // 主键生成配置
        result.setKeyGeneratorConfig(getKeyGeneratorConfigurationForTOrder());
        return result;
    }
    //主键操作的生成策略
    private KeyGeneratorConfiguration getKeyGeneratorConfigurationForTOrder() {
        Properties keyGeneratorProp = getKeyGeneratorProperties();
        return new KeyGeneratorConfiguration("SNOWFLAKE", "order_id", keyGeneratorProp);
    }

    // 获取相关的Order订单规则表配置信息控制配置控制机制
    TableRuleConfiguration getOrderItemTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration("t_order_item", "ds${0..1}.t_order_item${0..1}");
        result.setKeyGeneratorConfig(getKeyGeneratorConfigurationForTOrderItem());
        return result;
    }

    // 创建相关keyOrderItem机制控制操作
	private KeyGeneratorConfiguration getKeyGeneratorConfigurationForTOrderItem() {
        Properties keyGeneratorProp = getKeyGeneratorProperties();
        return new KeyGeneratorConfiguration("SNOWFLAKE", "id", keyGeneratorProp);
    }

  // 生成键值相关的generator的配置信息控制
    private Properties getKeyGeneratorProperties() {
        Properties keyGeneratorProp = new Properties();
        String distributeProcessIdentify = NetUtils.getLocalAddress() + ":" + getProcessId();
        String workId = String.valueOf(convertString2Long(distributeProcessIdentify));
        keyGeneratorProp.setProperty("worker.id", workId);
        LogUtils.info(log, "shardingsphere init", "shardingsphere work id raw string is {}, work id is {}", distributeProcessIdentify, workId);
        return keyGeneratorProp;
    }

    // 数据源相关配置机制
    Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> result = new HashMap<>();
        result.put("ds0", DataSourceUtils.createDataSource("ds0"));
        result.put("ds1", DataSourceUtils.createDataSource("ds1"));
        return result;
    }

	// 常见相关的workerid和dataid对应相关的进程id
    private String getProcessId(){
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        return pid;
    }

	// 转换字符串成为相关的long类型
    private Long convertString2Long(String str){
        long hashCode = str.hashCode() + System.currentTimeMillis();
        if(hashCode < 0){
            hashCode = -hashCode;
        }
        return hashCode % (1L << 10);
    }
}
ShardingsphereMybatisConfig 配置机制
/**
 * @Author zhangboqing
 * @Date 2020/4/23
 */
@Configuration
@MapperScan(basePackages = "com.zbq.springbootshardingjdbcjavaconfigdemo.dao",sqlSessionFactoryRef = "sqlSessionFactoryForShardingjdbc")
public class ShardingsphereMybatisConfig {
    @Autowired
    @Qualifier("shardingDataSource")
    private DataSource dataSource;
    @Bean("sqlSessionFactoryForShardingjdbc")
    public SqlSessionFactory sqlSessionFactoryForShardingjdbc() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
//        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().
//                getResources("classpath*:**/*.xml"));
        sessionFactory.setTypeAliasesPackage("com.zbq.springbootshardingjdbcjavaconfigdemo.domain.entity");
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        sessionFactory.setConfiguration(configuration);
        return sessionFactory.getObject();
    }
}
ShardingsphereTransactionConfig 配置机制

主要定制化配置事务操作可以空战未来的,为了未来的查询扩展XA


@Configuration
@EnableTransactionManagement
public class ShardingsphereTransactionConfig {
    @Bean
    @Autowired
    public PlatformTransactionManager shardingsphereTransactionManager(@Qualifier("shardingDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

标签:分库,SpringBoot,数据源,配置,算法,分片,new,ShardingJDBC,order
来源: https://www.cnblogs.com/liboware/p/15166006.html