基于shardingsphere的读写分离方案

pom文件配置

xml 复制代码
<!-- Mybatis Plus的依赖,包括Mybatis和Mybatis Plus的核心库 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>

<!-- ShardingSphere的依赖 -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>5.0.0-alpha</version>
</dependency>

<!-- MySQL数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>

接着,我们需要在application.yml中进行相关配置。

ShardingSphere配置

yaml 复制代码
spring:
  # 配置数据源
  shardingsphere:
    datasource:
      # 配置主库
      master:
        url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&serverTimezone=UTC
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
      # 配置从库1
      slave0:
        url: jdbc:mysql://127.0.0.1:3307/test?useSSL=false&serverTimezone=UTC
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
      # 配置从库2
      slave1:
        url: jdbc:mysql://127.0.0.1:3308/test?useSSL=false&serverTimezone=UTC
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
    # 配置读写分离规则
    sharding:
      default-data-source: master # 默认使用主库
      master-slave-rules:
        # 配置读写分离规则,每个库都是一主多从
        ms0:
          master-data-source-name: master
          slave-data-source-names:
            - slave0
            - slave1
          # 配置负载均衡算法,这里设置轮询策略
          load-balance-algorithm-type: round_robin

对应java代码

我们在MybatisPlusConfig中配置相关的Interceptor和DataSource。

java 复制代码
@Configuration
public class MybatisPlusConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean(name = "myRoutingDataSource")
    public DataSource myRoutingDataSource() throws SQLException {
        Map<String, DataSource> dataSourceMap = new HashMap<>(3);
        dataSourceMap.put("master", dataSource);
        dataSourceMap.put("slave0", createDataSource("jdbc:mysql://127.0.0.1:3307/test?useSSL=false&serverTimezone=UTC", "root", "123456"));
        dataSourceMap.put("slave1", createDataSource("jdbc:mysql://127.0.0.1:3308/test?useSSL=false&serverTimezone=UTC", "root", "123456"));

        ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
        shardingRuleConfiguration.setDefaultDataSourceName("master");

        // 配置分片规则
        shardingRuleConfiguration.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", new ModuloShardingTableAlgorithm()));
        shardingRuleConfiguration.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", new ModuloShardingTableAlgorithm()));

        // 配置读写分离规则
        shardingRuleConfiguration.setMasterSlaveRuleConfigs(Collections.singletonList(new MasterSlaveRuleConfiguration("ms0", "master", Arrays.asList("slave0", "slave1"))));

        return ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, Collections.singleton(shardingRuleConfiguration), new Properties());
    }

    private DataSource createDataSource(final String url, final String username, final String password) {
        HikariDataSource result = new HikariDataSource();
        result.setDriverClassName("com.mysql.cj.jdbc.Driver");
        result.setJdbcUrl(url);
        result.setUsername(username);
        result.setPassword(password);
        return result;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(myRoutingDataSource());
        factoryBean.setPlugins(mybatisPlusInterceptor());
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

}

在这个配置中,我们创建了一个myRoutingDataSource,用于管理我们的多数据源。在这里,我们将master库作为默认数据源,然后配置了两个从库(slave0和slave1)。

接着,我们还需要配置分片规则和读写分离规则。这里,我们简单地配置了一下按照user_id字段进行分片,并按照轮询策略进行负载均衡的读写分离规则。

最后,在我们的Mapper接口中,我们可以使用@DS注解来指定数据源。

less 复制代码
public interface UserMapper extends BaseMapper<User> {
    @DS("master") // 指定数据源为主库
    @Override
    int insert(User entity);
    @DS("slave") // 指定数据源为从库
    @Override
    User selectById(Serializable id);
    @DS("slave")
    List<User> selectListByUserId(Integer userId);
}

这样,我们就完成了基于SpringBoot、Mybatis Plus、ShardingSphere实现读写分离的方案!

补充:

  1. 在数据库中建立表时,需要按照分片规则进行建表。例如,我们按照user_id进行分片,则需要对每个分片建立对应的表,例如user_0user_1等。在进行增删改查操作时,需要根据user_id进行路由。
  2. 在进行读写分离时,需要考虑到数据同步的问题。即,当主库增加或修改数据时,需要同步到从库中。在ShardingSphere中,可以设置同步方式,例如异步或同步等。
  3. 在ShardingSphere中,除了读写分离外,还有更多的分片策略可供选择。例如,按照哈希值进行分片、按照范围进行分片等等。根据实际场景选择合适的分片策略可以更好地提升性能。
  4. 在进行多数据源管理时,需要考虑到事务问题。例如,如果一个事务中需要涉及到多个数据源,就需要使用分布式事务来管理。ShardingSphere提供了XA、AT等分布式事务方案。
  5. 最好将ShardingSphere的配置分离出去,不要将其配置在application.yml中,这样更易于维护和管理。可以将配置写在单独的yaml文件中,并通过spring.config.import属性将其导入到SpringBoot中,例如:
yaml 复制代码
 # sharding-jdbc.yaml
spring:
  shardingsphere:
    # 配置数据源、分片规则和读写分离规则

然后,在application.yml中导入这个配置文件:

arduino 复制代码
# application.ymlspring:
  config:
    import: classpath:sharding-jdbc.yml
  1. 在ShardingSphere中,如果有多个表需要采用相同的分片策略,可以使用逻辑表来简化配置。例如,我们有两个表userorder,按照user_id进行分片,可以这样配置:
yaml 复制代码
 # 配置逻辑表user_order
tables:
  user_order:
    actualDataNodes: ds${0..1}.user_${0..3} # 分片规则# 其他配置
  1. 在进行数据分片时,需要考虑到数据分布的均衡问题。如果某个分片的数据量过大,会导致性能下降。可以考虑将分片键设计得更加合理,以实现数据分布的均衡。
  2. 在进行读写分离时,需要考虑到数据同步的问题。如果在从库上发生了读取操作,但是在主库中进行了写入操作,那么数据就会出现不一致的情况。可以考虑使用异步复制或半同步复制等机制来解决这个问题。
  3. 在ShardingSphere中,可以使用tracing-enabled属性来启用分片日志,以便于定位错误和问题。
  4. 最后,需要注意分片的成本和维护的难度。尽管分片可以提高系统性能,但是需要付出更多的成本和维护的难度。在进行分片之前,需要对系统架构进行全面的评估,并权衡利弊。
相关推荐
Hello-Brand2 分钟前
Java核心知识体系10-线程管理
java·高并发·多线程·并发·多线程模型·线程管理
乐悠小码8 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.9 分钟前
Pod控制器
java·开发语言
2的n次方_12 分钟前
二维费用背包问题
java·算法·动态规划
皮皮林55112 分钟前
警惕!List.of() vs Arrays.asList():这些隐藏差异可能让你的代码崩溃!
java
莳光.13 分钟前
122、java的LambdaQueryWapper的条件拼接实现数据sql中and (column1 =1 or column1 is null)
java·mybatis
程序猿麦小七18 分钟前
基于springboot的景区网页设计与实现
java·spring boot·后端·旅游·景区
weisian15124 分钟前
认证鉴权框架SpringSecurity-2--重点组件和过滤器链篇
java·安全
蓝田~26 分钟前
SpringBoot-自定义注解,拦截器
java·spring boot·后端
theLuckyLong27 分钟前
SpringBoot后端解决跨域问题
spring boot·后端·python