ShardingSphere实战(4)- 广播表和默认数据源

上篇博客,我们讲了 ShardingSphere实战(3)- 快速实现分库分表 ,这篇博客,我们解决分库分表以后遗留的两个小问题。

一、广播表

1. 广播表介绍

广播表(Broadcast Table)是一种特殊的表类型,常见于分布式数据库系统中,如在Apache ShardingSphere等数据库中间件中被广泛应用。广播表的设计目的是为了处理那些数据量相对较小,但需要频繁参与跨分片查询或关联操作的表。

  • 广播表的特点:
    • 数据冗余:广播表在每一个数据分片(或数据库节点)中都有一个完整的副本,这意味着数据在每个节点上都是完全相同的。
    • 读取优化:由于每个节点都有完整数据,对于涉及广播表的查询可以直接在本地节点完成,无需进行跨节点通信,从而提高查询效率。
    • 更新控制:由于广播表的数据在所有节点上都需要保持一致,因此对广播表的更新操作需要被严格控制,以避免数据不一致的问题。
  • 使用场景:
    • 配置表:存储系统配置信息,如枚举值、状态码等,这类数据通常变化不大,但需要在查询时快速访问。
    • 字典表:存储一些固定的对照关系,如地区代码与名称的对照表。
    • 关联表:当一个表需要与多个分片的主表进行关联查询时,可以考虑使用广播表来减少跨分片的JOIN操作。

2. 广播表配置

基于上篇博客配置的前提下(上篇博客的最后放上了完整的配置,需要的可以去看看,这里就不重复写上去了),加上广播表的配置:

# 配置广播表
spring.shardingsphere.sharding.broadcast-tables=t_config

在这里插入图片描述

3. 测试

/**
     * 广播表测试-保存
     */
    @GetMapping("/test5")
    public String test5(@RequestParam("count") Integer count) {
   
   

        Date now = new Date();
        for (int i = 0; i < count; i++) {
   
   
            ConfigDO configDO = new ConfigDO();
            configDO
<think>我们有一个需求:在SpringBoot项目中同时集成ShardingSphere(用于分库分表dynamic-datasource(用于多数据源切换)。目标是对需要分片的SQL使用ShardingSphere数据源,对不需要分片的SQL使用普通数据源(通过dynamic-datasource切换)。参考引用内容:[^1][^3]提到使用Shardingspheredynamic-datasource结合,将ShardingSphere管理的数据源作为dynamic-datasource管理的一个数据源,这样我们就可以通过dynamic-datasource的注解来切换数据源。[^2]提到将不分片的数据源独立出来,通过多数据源自主选择处理不同情况。实现思路:1.配置多个数据源,包括一个主数据源(由dynamic-datasource管理)ShardingSphere数据源(实际上ShardingSphere数据源本身也是由多个数据源组成,但我们将它作为一个逻辑数据源加入到dynamic-datasource中)。2.使用dynamic-datasource作为数据源切换的核心,将ShardingSphere数据源注册为其中一个数据源(比如命名为sharding)。3.在需要分片操作的地方,我们切换到sharding数据源;在不需要分片的地方,使用其他普通数据源。步骤:1.添加依赖(参考引用中的版本,但请注意版本兼容性,这里使用较新版本可能需要调整):-ShardingSphere:`sharding-jdbc-spring-boot-starter`-dynamic-datasource:`dynamic-datasource-spring-boot-starter`2.配置数据源-在application.yml中配置dynamic-datasource的多数据源,其中包含一个或多个普通数据源一个ShardingSphere数据源-注意:ShardingSphere数据源的配置需要单独放在一个命名空间下(比如shardingsphere.datasource),然后通过dynamic-datasource的配置将其引入。3.由于dynamic-datasourceShardingSphere的配置可能存在冲突(因为两者都会创建数据源),我们需要将ShardingSphere数据源配置为dynamic-datasource的一个子数据源。具体配置示例(application.yml):注意:以下配置仅为示例,请根据实际情况调整。```yamlspring:#动态数据源配置datasource:dynamic:primary:master#设置默认数据源datasource:master:#主库,不参与分片的数据源url:jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=utf8&useSSL=falseusername:rootpassword:rootdriver-class-name:com.mysql.jdbc.Driver#可以配置其他普通数据源,比如slave1,slave2等sharding:enabled:true#开启shardingsphere,这里我们将其作为一个数据源#注意:这里不能直接配置shardingsphere数据源,因为dynamic-datasource并不直接支持shardingsphere的配置方式#因此,我们需要在另一个地方配置shardingsphere,并将其数据源对象注入到dynamic-datasource中#但是,上述方式在dynamic-datasource中直接配置sharding是不行的,因为dynamic-datasource无法解析shardingsphere的复杂配置。#因此,我们需要换一种方式:将ShardingSphere数据源配置在shardingsphere的命名空间下,然后在dynamic-datasource中引用这个数据源。#实际上,我们可以这样:#1.配置shardingsphere数据源(多个,用于分片)#2.然后,shardingsphere会创建一个逻辑数据源(我们假设叫shardingDataSource)#3.将这个shardingDataSource通过编程方式注册到dynamic-datasource的数据源集合中。但是,dynamic-datasource官方提供了多种方式集成,其中一种就是通过编程方式添加数据源。因此,我们可以:1.配置多个普通数据源(通过dynamic-datasource的配置方式)。2.配置ShardingSphere数据源(通过shardingsphere的配置方式),但不将其作为spring的主数据源。3.在程序启动后,将ShardingSphere创建的数据源对象添加到dynamic-datasource的数据源容器中。然而,引用[3]中提到:将Shardingsphere管理的数据源加入dynamic-datasource。所以我们可以这样配置:另一种配置方式(推荐):将ShardingSphere的配置完全独立,然后通过dynamic-datasource的`datasource`配置项来引入一个名为`sharding`的数据源,但是这个数据源实际上是由ShardingSphere创建的。但是,dynamic-datasource的配置中只能配置普通数据源,不能配置ShardingSphere数据源。所以我们需要通过编程方式。参考引用[2]中的方法:将不分片的数据源独立出来,通过多数据源自主选择。这里我们采用编程方式集成。步骤:1.配置ShardingSphere数据源(使用shardingsphere的配置规则)。2.配置dynamic-datasource,其中包含除了ShardingSphere数据源之外的其他普通数据源。3.在Spring容器启动后,获取ShardingSphere创建的数据源对象,然后将其添加到dynamic-datasource的数据源容器中,并指定一个名称(比如"sharding")。具体实现:首先,在pom.xml中添加依赖(注意版本兼容,这里以引用中的版本为例,实际中可能需要选择兼容SpringBoot版本的依赖):```xml<dependencies><!--ShardingSphere--><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><!--dynamic-datasource--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.2.1</version></dependency><!--其他依赖--></dependencies>```然后,在application.yml中配置:```yaml#配置ShardingSphere(注意:这里使用shardingsphere的配置前缀)shardingsphere:datasource:names:ds0,ds1#两个物理数据源,用于分片ds0:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.jdbc.Driverjdbc-url:jdbc:mysql://localhost:3306/ds0?useUnicode=true&characterEncoding=utf8&useSSL=falseusername:rootpassword:rootds1:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.jdbc.Driverjdbc-url:jdbc:mysql://localhost:3306/ds1?useUnicode=true&characterEncoding=utf8&useSSL=falseusername:rootpassword:root#分片规则配置(这里只是一个示例,具体规则根据业务)sharding:tables:t_order:actual-data-nodes:ds$->{0..1}.t_order_$->{0..1}table-strategy:inline:sharding-column:order_idalgorithm-expression:t_order_$->{order_id%2}key-generator:column:order_idtype:SNOWFLAKE#配置dynamic-datasource(这里先配置普通数据源,sharding数据源后面通过代码加入)spring:datasource:dynamic:primary:master#默认数据源datasource:master:#主数据源,不参与分片url:jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=utf8&useSSL=falseusername:rootpassword:rootdriver-class-name:com.mysql.jdbc.Driver#可以配置其他普通数据源,比如slaveslave:url:jdbc:mysql://localhost:3306/slave?useUnicode=true&characterEncoding=utf8&useSSL=falseusername:rootpassword:rootdriver-class-name:com.mysql.jdbc.Driver```注意:上面的配置中,我们配置了ShardingSphere的两个物理数据源(ds0,ds1)以及分片规则,同时配置了dynamic-datasource的两个普通数据源(masterslave)。但是,我们还没有将ShardingSphere的逻辑数据源(即分片数据源)加入到dynamic-datasource中。接下来,我们需要编写一个配置类,在Spring启动后获取ShardingSphere创建的数据源,并将其添加到dynamic-datasource的数据源容器中。配置类示例:```javaimportcom.baomidou.dynamic.datasource.DynamicRoutingDataSource;importorg.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Configuration;importjavax.annotation.PostConstruct;importjavax.sql.DataSource;importjava.util.Map;@ConfigurationpublicclassDataSourceConfig{@AutowiredprivateDataSourcedataSource;//这里注入的是dynamic-datasource管理的动态数据源(DynamicRoutingDataSource)@AutowiredprivateShardingDataSourceshardingDataSource;//注入ShardingSphere创建的数据源@PostConstructpublicvoidinit(){//将shardingDataSource加入到动态数据源中(key为"sharding")DynamicRoutingDataSourcedynamicRoutingDataSource=(DynamicRoutingDataSource)dataSource;Map<String,DataSource>currentDataSources=dynamicRoutingDataSource.getCurrentDataSources();currentDataSources.put("sharding",shardingDataSource);dynamicRoutingDataSource.setDataSources(currentDataSources);//刷新数据源dynamicRoutingDataSource.afterPropertiesSet();}}```注意:上面的代码中,我们注入了两个数据源:1.第一个是`DataSource`,这个实际上是dynamic-datasource创建的动态路由数据源(DynamicRoutingDataSource),它管理着所有普通数据源。2.第二个是`ShardingDataSource`,这是ShardingSphere创建的数据源,它内部已经实现了分片逻辑。然后,在初始化方法中,我们将`ShardingDataSource`添加到`DynamicRoutingDataSource`管理的数据源集合中,并命名为"sharding"。这样,我们就可以在需要分片操作的地方使用`@DS("sharding")`注解来切换到ShardingSphere数据源了。对于不需要分片的操作,我们可以使用`@DS("master")`或`@DS("slave")`等。使用示例:```java@ServicepublicclassOrderService{//使用普通数据源(主库)执行非分片操作@DS("master")publicvoidaddUser(Useruser){//...操作非分片表}//使用sharding数据源执行分片操作@DS("sharding")publicvoidaddOrder(Orderorder){//...操作分片表}}```注意事项:1.版本兼容性:ShardingSpheredynamic-datasource的版本需要与SpringBoot版本兼容。2.配置顺序:确保ShardingSphere数据源配置正确,并且分片规则有效。3.在配置类中,我们直接注入了`ShardingDataSource`,这要求Spring容器中必须存在这个Bean。由于我们配置了ShardingSphere,它会自动创建一个`ShardingDataSource`的Bean,所以这里可以直接注入。4.动态添加数据源后,需要调用`afterPropertiesSet`方法刷新。如果遇到循环依赖问题,可以考虑使用`ObjectProvider`延迟注入。以上配置代码实现了将ShardingSphere数据源集成到dynamic-datasource中,从而实现多数据源切换分片数据源的统一管理。引用说明:本方案参考了引用[3]的思路,即“配置一个数据源,为主数据源,使用dynamic-datasource来管理数据源的切换,并且把Shardingsphere管理的数据源加入进去”,同时也参考了引用[2]中关于多数据源独立处理的思想[^2][^3]。§§相关问题§§1.在集成ShardingSpheredynamic-datasource时,如何解决数据源配置冲突?2.除了编程方式,还有其他方法将ShardingSphere数据源添加到dynamic-datasource中吗?3.在使用`@DS("sharding")`注解时,如何确保事务管理正确?</think>### Spring Boot 集成 ShardingSphere 与 dynamic-datasource 配置指南 #### 一、核心思路 1. **主数据源管理**:使用 dynamic-datasource 作为数据源切换核心 2. **分片数据源集成**:将 ShardingSphere 数据源作为 dynamic-datasource 的一个子数据源 3. **路由策略**: - 分片操作 → 路由到 ShardingSphere 数据源 - 非分片操作 → 路由到普通数据源(主库/从库) #### 二、依赖配置(pom.xml) ```xml <!-- ShardingSphere JDBC --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>5.3.2</version> <!-- 推荐最新稳定版 --> </dependency> <!-- dynamic-datasource --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>4.2.0</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> ``` #### 三、配置文件(application.yml) ```yaml spring: datasource: dynamic: primary: master # 默认数据源 strict: false # 非严格模式(允许未配置数据源) datasource: master: # 主库(不分片) url: jdbc:mysql://localhost:3306/master_db username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver slave1: # 从库(不分片) url: jdbc:mysql://localhost:3307/slave_db username: root password: 123456 # ShardingSphere 分片配置 spring: shardingsphere: datasource: names: sharding-ds # 逻辑数据源名称 sharding-ds: # 分片数据源配置 type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3310/shard_db username: shard_user password: shard_pwd rules: sharding: tables: order: # 分片表配置 actual-data-nodes: sharding-ds.order_$->{0..1} table-strategy: standard: sharding-column: user_id sharding-algorithm-name: table-mod sharding-algorithms: table-mod: type: MOD props: sharding-count: 2 props: sql-show: true # 显示SQL日志 ``` #### 四、数据源注册配置类 ```java @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.shardingsphere.datasource.sharding-ds") public DataSource shardingDataSource() { // 创建ShardingSphere数据源 return ShardingSphereDataSourceFactory.createDataSource( "sharding-ds", new Properties() ); } @Bean @Primary public DynamicRoutingDataSource dynamicDataSource( @Qualifier("shardingDataSource") DataSource shardingDS, DataSourceProperties properties ) { // 1. 创建dynamic-datasource核心组件 DynamicRoutingDataSource ds = new DynamicRoutingDataSource(); // 2. 注册所有数据源 Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("master", properties.initializeDataSourceBuilder().build()); dataSourceMap.put("sharding", shardingDS); // 关键:注册分片数据源 // 3. 设置数据源集合 ds.setDataSources(dataSourceMap); ds.setDefaultTargetDataSource(dataSourceMap.get("master")); return ds; } } ``` #### 五、业务层使用示例 ```java @Service public class OrderService { // 1. 普通数据源操作(非分片) @DS("master") // dynamic-datasource注解 public void createUser(User user) { // 操作非分片表 } // 2. 分片数据源操作 @DS("sharding") // 切换到ShardingSphere数据源 public void createOrder(Order order) { // 自动路由到分片表 // INSERT INTO order_${user_id % 2} ... } // 3. 读写分离(非分片) @DS("slave1") public List<User> queryUsers() { // 从只读库查询 } } ``` #### 六、关键注意事项 1. **事务管理**: ```java @Transactional(rollbackFor = Exception.class) @DS("sharding") // 必须注解在事务方法上 public void shardingTransaction() { ... } ``` 2. **配置优先级**: - 分片规则配置 > dynamic-datasource 配置 - 使用 `@DS` 注解优先于默认数据源 3. **动态数据源切换原理**: - 通过 `DataSourceHolder` 存储当前线程数据源key - `AbstractRoutingDataSource` 实现运行时动态路由 - ShardingSphere 在获取连接后执行分片路由[^3] --- ### 常见问题解决方案 1. **SQL语法限制问题** ```方案:``` 非分片SQL走普通数据源,避免ShardingSphere限制[^3] 2. **主库占用问题** ```方案:``` 读操作通过 `@DS("slave1")` 路由到从库[^1] 3. **配置冲突解决** ```方案:``` 确保 ShardingSphere 数据源bean名与dynamic-datasource注册key一致 --- ### 引用说明 本方案实现参考了以下实践: - ShardingSphere 分片数据源作为独立数据源集成到 dynamic-datasource 框架[^2] - 通过注解实现分片操作与非分片操作的隔离路由[^3] -数据源环境下的事务管理策略[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值