ShardingSphere-JDBC兼容dynamicDataSource实现多数据源

1. 背景

ShardingSphere-JDBC(5.1.1版本)读写分离示例一文中介绍了ShardingJdbc(5.1.1)的使用,但该文中方法没有使用DynamicDataSource,如果一起使用的话会出现异常(Caused by: java.lang.IllegalArgumentException: Property ‘sqlSessionFactory’ or ‘sqlSessionTemplate’ are required),如果想要一起使用或者将ShardingSphere-JDBC集成到原DynamicDataSource项目中则需要对数据源进行修改,本质上就是将shardingDataSource作为DynamicDataSource的一个数据源,将sharding的数据源交由原Dynamic管理。

2. 数据源配置

将sharding的数据源交由原Dynamic管理

@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, ShardingSphereAutoConfiguration.class})
@Slf4j
public class MrsszDataSourceConfig {
    @Autowired
    AbstractApplicationContext context;
    @Autowired
    private DynamicDataSourceProperties properties;
​
    @Lazy
    @Resource
    private DataSource shardingDataSource;
​
    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
        return new AbstractDataSourceProvider() {
            @Override
            public Map<String, DataSource> loadDataSources() {
                Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
                dataSourceMap.put("sharding-data-source", shardingDataSource);
                return dataSourceMap;
            }
        };
    }
​
    @Primary
    @Bean
    public DataSource dataSource() {
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
        dataSource.setStrict(properties.getStrict());
        dataSource.setStrategy(properties.getStrategy());
        dataSource.setP6spy(properties.getP6spy());
        dataSource.setSeata(properties.getSeata());
        String primary = "true".equals(this.context.getEnvironment().getProperty("spring.shardingsphere.enabled"))
                ? "sharding-data-source" : properties.getPrimary();
        dataSource.setPrimary(primary);
        log.info("Mrssz Datasource primary: {}", primary);
        return dataSource;
    }
}

同时在application.yml配置文件中新增Dynamic数据源

spring:
  application:
    name: readwrite-splitting
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: 'jdbc:mysql://127.0.0.1:3306/rw_master?characterEncoding=utf-8&useSSL=false'
          password: ***
          type: com.zaxxer.hikari.HikariDataSource
          username: root
          hikari:
            connection-timeout: 30000
            idle-timeout: 600000
            minimum-idle: 10
            maximum-pool-size: 10
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      pool-name: MrsszHikariCP
      connection-timeout: 30000
      idle-timeout: 600000
      minimum-idle: 10
      maximum-pool-size: 10
      auto-commit: true
3. 启动测试

修改配置后启动项目,能看到控制台打印日志中新增了两个数据源,一个是sharding的sharding-data-source,另一个是dynamic的master。
2022-06-12 23-24-54屏幕截图.png

4. 新增使用Dynamic数据源的方法

后续所有改动都是基于ShardingSphere-JDBC(5.1.1版本)读写分离示例做的修改。

4.1 controller层新增方法
    @GetMapping("/queryByMaster")
    public ReadWriteContentEntity getContentByMaster(@RequestParam int id) {
        return readWriteContentService.getContentByMaster(id);
    }
4.2 service层新增方法
    public ReadWriteContentEntity getContentByMaster(int id) {
        return readWriteContentMapper.getContentByMaster(id);
    }
4.3 dao层新增方法

不改动原本的sharding相关方法,写一个新方法标注使用@DS("master")数据源,如果该读到的是主库的数据而原sharding读的还是从库的话则说明同时生效了。

    @DS("master")
    ReadWriteContentEntity getContentByMaster(@Param("id") int id);
4.4 mapper层新增方法
    <select id="getContentByMaster" resultType="cn.mrssz.readwritesplitting.entity.ReadWriteContentEntity">
        SELECT * FROM t_content
        WHERE id = #{id}
    </select>
4. 效果测试

原query方法,预期读到从库的数据,正常

2022-06-12 23-52-48屏幕截图.png
新queryByMaster方法,预期读到主库的数据,正常

2022-06-12 23-52-27屏幕截图.png

5 其他

此外,值得注意的是baomidou的DynamicDataSource和ShardingSphere都是支持多数据源的,但是DynamicDataSource的多数据源存在事务异常不能回滚的问题,DynamicDataSource的多数据源方式难以支持跨数据源事务。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
1. 引入依赖 在 `pom.xml` 中引入 `shardingsphere-jdbc-core` 依赖: ```xml <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core</artifactId> <version>5.0.0-alpha</version> </dependency> ``` 2. 配置数据源 在 `application.yml` 中配置数据源: ```yaml spring: datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root password: root sharding: jdbc: # 数据源列表 datasource: ds0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/test0?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root password: root ds1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root password: root # 分片规则配置 sharding: default-data-source: ds0 # 默认数据源 tables: user: actual-data-nodes: ds${0..1}.user_${0..1} # 实际数据节点 database-strategy: inline: sharding-column: id # 分片键 algorithm-expression: ds${id % 2} # 分库算法 table-strategy: inline: sharding-column: id # 分片键 algorithm-expression: user_${id % 2} # 分表算法 ``` 3. 编写代码 ```java @Service public class UserServiceImpl implements UserService { @Autowired private JdbcTemplate jdbcTemplate; @Override public void addUser(User user) { String sql = "INSERT INTO user (id, name) VALUES (?, ?)"; Object[] params = new Object[] { user.getId(), user.getName() }; int count = jdbcTemplate.update(sql, params); System.out.println("插入 " + count + " 条记录"); } @Override public List<User> getUsers() { String sql = "SELECT * FROM user"; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class)); } } ``` 4. 测试 编写测试方法: ```java @SpringBootTest class UserServiceImplTest { @Autowired private UserService userService; @Test void addUser() { User user = new User(); user.setId(1L); user.setName("张三"); userService.addUser(user); } @Test void getUsers() { List<User> users = userService.getUsers(); System.out.println(users); } } ``` 执行测试方法,查看控制台输出和数据库表中的数据,验证分库分表是否成功实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值