基于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. 最后,需要注意分片的成本和维护的难度。尽管分片可以提高系统性能,但是需要付出更多的成本和维护的难度。在进行分片之前,需要对系统架构进行全面的评估,并权衡利弊。
相关推荐
一只叫煤球的猫4 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9655 小时前
tcp/ip 中的多路复用
后端
bobz9655 小时前
tls ingress 简单记录
后端
皮皮林5516 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友6 小时前
什么是OpenSSL
后端·安全·程序员
bobz9656 小时前
mcp 直接操作浏览器
后端
前端小张同学8 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook9 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康9 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在10 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net