基于 dynamic-datasource 实现 DB 多数据源及事物控制、读写分离、负载均衡解决方案

本文详细介绍了如何在SpringBoot项目中使用dynamic-datasource-spring-boot-starter实现多数据源配置、读写分离、事务控制以及负载均衡。通过配置数据源、使用@DS注解切换数据源、@DSTransactional进行事务管理,并通过自定义拦截器实现读写分离。此外,还展示了如何通过更改数据源组名实现负载均衡效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、dynamic-datasource

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

特征

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密 ENC()
  • 支持每个数据库独立初始化表结构schema和数据库database
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)
  • 提供并简化对DruidHikariCpBeeCpDbcp2的快速集成。
  • 提供对Mybatis-PlusQuartzShardingJdbcP6syJndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spelsessionheader,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)
  • 提供 基于seata的分布式事务方案。
  • 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。

约定

  • 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD
  • 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
  • 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
  • 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
  • 方法上的注解优先于类上注解。
  • DS支持继承抽象类上的DS,暂不支持继承接口上的DS

官方文档地址:https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611

下面分别从 多数据源及事物控制、读写分离实现、负载均衡实现三个方面进行实践。

二、环境准备

在实验开始前,先准备两个数据库,来进行实验测试:

create database db1;
create database db2;

在这里插入图片描述
然后在两个库中分别创建测试表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在这里插入图片描述
接着分别在db1 和 db2 中写入一条数据,数据id一致,但内容不一致,主要用于下面实验的区分:

db1:

INSERT INTO `user`(`id`, `name`, `age`) VALUES (1, '张三', 18);

db2:

INSERT INTO `user`(`id`, `name`, `age`) VALUES (1, '李四', 20);

下面首先创建一个 SpringBoot 项目,在 pom 中引入 dynamic-datasource 的依赖,以及 mysqlmybatisplus

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.23</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>

下面创建上面测试表的实体 entity

@Data
@TableName("user")
public class UserEntity {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
}

三、多数据源及事物控制

dynamic-datasource 针对于多数据源的切换推出了 @DS 注解,@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。

下面开始实施:

修改配置文件增加数据库连接:

server:
  port: 8080
spring:
  application:
    name: dynamic-datasource-demo
  autoconfigure:
    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  datasource:
    dynamic:
      primary: db1 #设置默认的数据源或者数据源组,默认值即为master
      strict: true #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
      datasource:
        db1:
          driver-class-name: com.mysql.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
          url: jdbc:mysql://10.32.33.148:3307/db1?useUnicode=true&characterEncoding=utf8
          username: root
          password: root123
        db2:
          driver-class-name: com.mysql.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
          url: jdbc:mysql://10.32.33.148:3307/db2?useUnicode=true&characterEncoding=utf8
          username: root
          password: root123

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.bxc.dynamicdatasourcedemo.entity

然后分别创建两个 DAO,并通过 @DS 切换数据源:

@Repository
@Mapper
@DS("db1")
public interface DB1UserDao extends BaseMapper<UserEntity>{
    @Insert("insert into user(name,age) values(#{name},#{age})")
    int addUser(UserEntity entity);
}
@Repository
@Mapper
@DS("db2")
public interface DB2UserDao extends BaseMapper<UserEntity> {
    @Insert("insert into user(name,age) values(#{name},#{age})")
    int addUser(UserEntity entity);
}

下面创建一个测试类测试一下是否正常:

@Slf4j
@SpringBootTest
class DynamicDatasourceDemoApplicationTests {

    @Autowired
    DB1UserDao db1UserDao;

    @Autowired
    DB2UserDao db2UserDao;

    @Test
    void test1() {
        UserEntity db1UserEntity = db1UserDao.selectById(1);
        log.info("db1 查询结果:{} ",db1UserEntity.toString());
        UserEntity db2UserEntity = db2UserDao.selectById(1);
        log.info("db2 查询结果:{} ",db2UserEntity.toString());
    }
}

在这里插入图片描述

已经实现多数据源查询效果,下面继续事物的控制,应该都了解在 Spring 中事物使用 @Transactional 注解即可,但是仅针对于单个数据源的情况,多数据源下我们可以使用 jta 来控制,不过在 dynamic-datasource 中又推出了 @DSTransactional 注解来代替 Spring@Transactional 注解,下面我们实验一下:

@Slf4j
@SpringBootTest
class DynamicDatasourceDemoApplicationTests {

    @Autowired
    DB1UserDao db1UserDao;

    @Autowired
    DB2UserDao db2UserDao;

    @Test
    @DSTransactional
    void test1() {
        UserEntity entity = new UserEntity();
        entity.setName("王五");
        entity.setAge(16);
        int db1 = db1UserDao.insert(entity);
        log.info("db1写入个数:{} ", db1);
        int db2 = db2UserDao.insert(entity);
        log.info("db2写入个数:{} ", db2);
        //模拟异常
        int a = 1 / 0;
    }
}

在这里插入图片描述
在这里插入图片描述
数据已经回滚!

四、读写分离

从上面的步骤中,已经了解到了 @DS 这个注解,那么通过这个注解我们可以简单的实现下读写分离结构,比如:

@Repository
@Mapper
public interface DBUserDao  {

    @DS("db1")
    @Insert("insert into user(name,age) values(#{name},#{age})")
    int addUser(UserEntity entity);

    @DS("db2")
    @Select("select * from user where id = #{id}")
    UserEntity findUser(@Param("id") Long id);
}

不过这种方式有点繁琐,每个 dao 都需要添加注解,那我们是不是可以通过 mybatis 的拦截器来完成呢,下面开始操作下:

创建一个 mybatis 的拦截器:

@Intercepts({@Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
), @Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class}
)})
@Slf4j
@Component
@Primary
public class MasterSlaveAutoRoutingPlugin implements Interceptor {

    private static final String MASTER = "db1";

    private static final String SLAVE = "db2";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        try {
            DynamicDataSourceContextHolder.push(SqlCommandType.SELECT == ms.getSqlCommandType() ? SLAVE : MASTER);
            return invocation.proceed();
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
    }

    @Override
    public Object plugin(Object target) {
        return target instanceof Executor ? Plugin.wrap(target, this) : target;
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

修改上面的 Dao 去除 @DS 注解:

@Repository
@Mapper
public interface DBUserDao {

    @Insert("insert into user(name,age) values(#{name},#{age})")
    int addUser(UserEntity entity);

    @Select("select * from user where id = #{id}")
    UserEntity findUser(@Param("id") Long id);
}

测试:

@Slf4j
@SpringBootTest
class DynamicDatasourceDemoApplicationTests {

    @Autowired
    DBUserDao dbUserDao;

    @Test
    void test2() {
        UserEntity entity = new UserEntity();
        entity.setName("王五");
        entity.setAge(16);
        int update = dbUserDao.addUser(entity);
        log.info("写入个数:{} ", update);
        UserEntity user = dbUserDao.findUser(1L);
        log.info("读取数据:{} ", user.toString());
    }
}

在这里插入图片描述

通过日志可以看出,读取的数据库是 db2 ,而写入的数据库呢,来看下db1 中的内容:

在这里插入图片描述
已经实现读写分离的效果。

五、负载均衡

上面通过 mybatis 的拦截器实现了读写分离,同时 dynamic-datasource 还为我们提供了负载的效果,同一个组下的默认就是负载均衡效果,怎么才是同一个组呢,上面有提到只需以下划线 _ 分割即可,下面修改配置文件:

spring:
  application:
    name: dynamic-datasource-demo
  autoconfigure:
    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  datasource:
    dynamic:
      primary: db_1 #设置默认的数据源或者数据源组,默认值即为master
      strict: true #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
      datasource:
        db_1:
          driver-class-name: com.mysql.cj.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
          url: jdbc:mysql://10.32.33.148:3307/db1?useUnicode=true&characterEncoding=utf8
          username: root
          password: root123
        db_2:
          driver-class-name: com.mysql.cj.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
          url: jdbc:mysql://10.32.33.148:3307/db2?useUnicode=true&characterEncoding=utf8
          username: root
          password: root123

声明 Dao ,指定数据源为 db

@Mapper
@Repository
@DS("db")
public interface FindUserDao extends BaseMapper<UserEntity> {
}

测试:

在这里插入图片描述
可以看到明显的负载轮训效果了。

<think>我们面对的需求是:在若依微服务框架中,使用 dynamic-datasource-spring-boot-starter 来集成 ShardingSphere 的读写分离数据源。 但是注意,用户要求的是配置 dynamic-datasource-spring-boot-starter 以支持 ShardingSphere 的读写分离数据源,而不是直接用ShardingSphere替换动态数据源。 根据引用,dynamic-datasource-spring-boot-starter 本身是一个多数据源管理工具,而ShardingSphere是一个分库分表、读写分离的框架。 我们想要结合两者,即利用dynamic-datasource管理多个数据源(可能是不同的业务库),而每个业务库内部又需要ShardingSphere来实现读写分离。 然而,需要注意的是:ShardingSphere本身也可以管理多个数据源(分片数据源和读写分离数据源),所以两者在功能上有重叠。因此,我们需要明确如何整合。 一种常见的整合方式是: 1. 使用dynamic-datasource管理多个数据源,其中每个数据源实际上是一个ShardingSphere数据源(已经配置了读写分离)。 2. 这样,我们可以通过dynamic-datasource切换不同的业务数据源(每个业务数据源内部由ShardingSphere管理读写分离)。 具体步骤: 步骤1:引入依赖 需要同时引入 dynamic-datasource-spring-boot-starter 和 sharding-jdbc-spring-boot-starter 依赖。 步骤2:配置多个数据源(每个数据源对应一个ShardingSphere数据源) 在application.yml中配置dynamic-datasource的数据源,但是每个数据源不是普通的DataSource,而是一个ShardingSphereDataSource。 但是,dynamic-datasource默认不支持直接配置ShardingSphere数据源,因此我们需要通过编程方式创建ShardingSphere数据源,并将其注册为dynamic-datasource的数据源。 步骤3:通过编程方式创建ShardingSphere数据源 我们可以为每个需要读写分离的数据源分别配置一个ShardingSphere数据源,然后交给dynamic-datasource管理。 步骤4:使用@DS注解切换数据源,同时每个数据源内部由ShardingSphere实现读写分离。 但是,这种整合方式可能会比较复杂,因为ShardingSphere的配置本身也比较复杂。 另一种思路(更简单):将ShardingSphere的读写分离数据源作为一个普通数据源注册到dynamic-datasource中。 即,我们配置一个ShardingSphere数据源(它已经包含了主库和从库,并实现读写分离),然后将这个ShardingSphere数据源作为一个数据源(比如叫做"sharding-db")注册到dynamic-datasource中。 这样,我们可以用@DS("sharding-db")来使用这个数据源,同时在这个数据源内部实现读写分离。 具体配置示例: 1. 引入依赖(注意版本兼容性): ```xml <!-- dynamic-datasource --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- sharding-jdbc --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency> ``` 2. 配置ShardingSphere的读写分离数据源(以其中一个业务库为例,假设我们有两个业务库:order和user,每个业务库都需要读写分离): 但是注意,dynamic-datasource和sharding-jdbc的配置会有冲突,因为它们都会去创建数据源。因此,我们禁用sharding-jdbc的自动配置,改为手动创建ShardingSphere数据源。 3. 通过@Bean手动创建ShardingSphere数据源,并将其注册到dynamic-datasource中。 配置示例(application.yml): ```yaml spring: datasource: dynamic: primary: master # 设置默认的数据源或者数据源组,默认值即为master strict: false # 严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: master: # 这是默认数据源(可以是一个普通数据源,也可以是一个ShardingSphere数据源,但我们这里用普通数据源作为其他非分片库) url: jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver # 注意:我们不在这里配置sharding-db,而是通过@Bean配置 ``` 然后,我们创建一个配置类,手动创建ShardingSphere数据源(例如,名为sharding-db),并将其注册到dynamic-datasource的数据源集合中。 配置类示例: ```java @Configuration public class ShardingDataSourceConfig { @Autowired private DataSourceProperties dataSourceProperties; // 假设我们有一个主库和两个从库,用于读写分离 @Bean @ConfigurationProperties(prefix = "spring.datasource.sharding.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.sharding.slave0") public DataSource slave0DataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.sharding.slave1") public DataSource slave1DataSource() { return DataSourceBuilder.create().build(); } // 创建ShardingSphere数据源(读写分离) @Bean public DataSource shardingDataSource() throws SQLException { // 实际数据源映射 Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("master0", masterDataSource()); dataSourceMap.put("slave0", slave0DataSource()); dataSourceMap.put("slave1", slave1DataSource()); // 读写分离规则 MasterSlaveRuleConfiguration masterSlaveRuleConfig = new MasterSlaveRuleConfiguration( "sharding-db", // 读写分离数据源的名称(逻辑数据源名) "master0", // 主库数据源名称 Arrays.asList("slave0", "slave1") // 从库数据源名称列表 ); // 创建ShardingSphere数据源 return MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, masterSlaveRuleConfig, new Properties()); } // 将ShardingSphere数据源注册到dynamic-datasource中 @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { Map<String, DataSource> dataSourceMap = new HashMap<>(); try { // 将shardingDataSource加入到dynamic-datasource的数据源列表中 dataSourceMap.put("sharding-db", shardingDataSource()); } catch (SQLException e) { throw new RuntimeException(e); } return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { return dataSourceMap; } }; } } ``` 4. 在application.yml中,我们还需要配置dynamic-datasource的其他数据源(如果有的话)以及默认数据源。 5. 使用:在需要访问读写分离数据源的地方,使用@DS("sharding-db")注解。 注意:这种方式下,sharding-db这个数据源内部已经实现读写分离(由ShardingSphere管理),而其他数据源(如master)则是一个普通数据源。 但是,上述配置中,我们手动创建了多个数据源(masterDataSource, slave0DataSource, slave1DataSource)并组合成ShardingSphere数据源,然后将其注册到dynamic-datasource中。 另外,我们还需要在配置文件中配置这些数据源的连接信息,例如: ```yaml spring: datasource: dynamic: primary: master # 默认数据源 datasource: master: url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver sharding: master: url: jdbc:mysql://master-host:3306/db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave0: url: jdbc:mysql://slave0-host:3306/db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave1: url: jdbc:mysql://slave1-host:3306/db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver ``` 注意:上面的配置中,我们使用了自定义的配置前缀(spring.datasource.sharding)来配置ShardingSphere所需的主从数据源。 另外,由于我们手动创建了数据源,所以不需要ShardingSphere的自动配置,因此可以排除ShardingSphere的自动配置类: ```java @SpringBootApplication(exclude = {ShardingSphereAutoConfiguration.class}) ``` 这样,我们就实现了将ShardingSphere的读写分离数据源作为一个数据源整合到dynamic-datasource中。 但是,请注意:如果同时有多个这样的读写分离数据源(比如多个业务库,每个库都需要读写分离),那么我们需要为每个读写分离数据源创建一个ShardingSphere数据源,并注册到dynamic-datasource中。 总结:通过将ShardingSphere数据源作为dynamic-datasource的一个数据源,我们可以在使用dynamic-datasource切换数据源的同时,在特定的数据源内部使用ShardingSphere实现读写分离。 注意:这种整合方式可能比较复杂,需要仔细处理依赖和配置。同时,版本兼容性也是一个需要注意的问题。 如果遇到问题,建议查看官方文档或社区支持。 由于整合过程较为复杂,这里只提供了一个基本的思路和示例。</think>### 配置 dynamic-datasource-spring-boot-starter 集成 ShardingSphere 读写分离数据源 #### 核心思路 将 ShardingSphere 的读写分离数据源作为 dynamic-datasource 的一个独立数据源进行管理,通过 `@DS` 注解实现动态切换[^1][^3]。 #### 配置步骤 1. **添加依赖** ```xml <!-- dynamic-datasource 核心依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- ShardingSphere JDBC 依赖 --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>5.3.2</version> </dependency> ``` 2. **配置数据源(application.yml)** ```yaml spring: shardingsphere: # 关闭ShardingSphere自动数据源创建 enabled: false datasource: names: master,slave0,slave1 # 物理数据源名称 master: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://master-host:3306/db username: root password: master-pwd slave0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://slave0-host:3306/db username: root password: slave-pwd slave1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc://slave1-host:3306/db username: root password: slave-pwd datasource: dynamic: primary: default # 默认数据源 strict: true # 严格匹配模式 datasource: default: # 普通数据源 url: jdbc:mysql://default-host:3306/default_db username: user password: pass sharding-db: # ShardingSphere读写分离数据源(通过Bean配置) ``` 3. **创建 ShardingSphere 数据源 Bean** ```java @Configuration public class ShardingDataSourceConfig { @Bean("shardingDataSource") public DataSource shardingDataSource( @Qualifier("master") DataSource master, @Qualifier("slave0") DataSource slave0, @Qualifier("slave1") DataSource slave1) { // 1. 创建数据源映射 Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("master", master); dataSourceMap.put("slave0", slave0); dataSourceMap.put("slave1", slave1); // 2. 配置读写分离规则 MasterSlaveRuleConfiguration ruleConfig = new MasterSlaveRuleConfiguration( "sharding-db", // 逻辑数据源名称 "master", // 主库名称 Arrays.asList("slave0", "slave1") // 从库列表 ); // 3. 创建ShardingSphere数据源 try { return MasterSlaveDataSourceFactory.createDataSource( dataSourceMap, ruleConfig, new Properties() ); } catch (SQLException e) { throw new RuntimeException("创建ShardingSphere数据源失败", e); } } } ``` 4. **注册到 dynamic-datasource** ```java @Configuration public class DynamicDataSourceConfig { @Autowired private DataSource shardingDataSource; // 注入ShardingSphere数据源 @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { Map<String, DataSource> dsMap = new HashMap<>(); // 添加ShardingSphere数据源 dsMap.put("sharding-db", shardingDataSource); return dsMap; } }; } } ``` 5. **使用读写分离数据源** ```java @Service public class OrderService { // 使用普通数据源 public void defaultOperation() { // 默认使用default数据源 } // 使用ShardingSphere读写分离数据源 @DS("sharding-db") // 动态切换数据源注解[^1][^3] public void readOperation() { // 自动路由到从库 jdbcTemplate.query("SELECT * FROM orders"); } @DS("sharding-db") @Transactional public void writeOperation() { // 自动路由到主库 jdbcTemplate.update("INSERT INTO orders (...) VALUES (...)"); } } ``` #### 关键配置说明 1. **数据源层级结构**: ``` Dynamic-Datasource ├── default (普通数据源) └── sharding-db (ShardingSphere数据源) ├── master (物理主库) ├── slave0 (物理从库1) └── slave1 (物理从库2) ``` 2. **读写分离规则**: - 写操作自动路由到主库 - 读操作自动负载均衡到从库 - 事务内强制走主库 3. **动态切换机制**: - `@DS("sharding-db")` 注解将当前操作切换到 ShardingSphere 数据源 - 未注解方法使用默认数据源[^1][^3] #### 性能优化建议 1. **从库负载均衡**: ```java // 在ShardingSphere配置中添加负载均衡策略 ruleConfig.setLoadBalanceAlgorithmType("ROUND_ROBIN"); ``` 2. **连接池配置**: ```yaml master: hikari: maximum-pool-size: 20 minimum-idle: 5 slave0: hikari: maximum-pool-size: 15 ``` 3. **强制主库读取**: ```java @DS("sharding-db") @Transactional public void readFromMaster() { // 通过HintManager强制走主库 try (HintManager hintManager = HintManager.getInstance()) { hintManager.setMasterRouteOnly(); jdbcTemplate.query("SELECT * FROM orders"); } } ``` > **验证方法**:在 SQL 前添加 `/* ShardingSphere hint: master */` 注释可验证主库路由
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小毕超

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值