【Java】ruoyi框架,添加ShardingJdbc支持分库分表

1、 调研,目前主流的有Mycat、Sharding Jdbc ,准备选用后者;

分库分表,一种是按照时间范围进行,另外一种按照某个字段为分片键;

我这里,选用表数据中的DeptId字段作为分片键,这样能够保证同一个部门下的数据 能够分布到同一个数据库下的同一张表中,避免跨库操作带来性能损失以及跨库操作带来的事物问题;

2、项目实战
2.1 配置项目环境

(1)添加项目pom

<dependency>
	<groupId>org.apache.shardingsphere</groupId>
	<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
	<version>4.1.1</version>
</dependency>
2.2 配置添加

(1)添加配置 application-sharding.yml(这部分主要是为了区分开分库分表的配置文件和其他,当然也可以直接在原有的配置文件基础上添加)

我这边默认按照两个数据库进行操作,其中处理了开票记录表和明细表 如有需要自己添加 ;

我这边分片键按照部门ID进行对2取余数,这样能够保证同一个部门下的数据能够到相同的数据库下相同的表中,避免了跨库操作;分片键可以自己进行调整 。

为什么是对2取余数?因为目前总共分出来2个数据库,dev_0、dev_1 如果是三个 那就是对3取余,总之 能够保证取余之后的范围在 0~n-1 ,n对应的是分出来的库数量。表也是一样的,我这边默认按照和库一样的规则。

spring:
  shardingsphere:
    enabled: true # 是否开启分库分表
    datasource:
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/xxx_dev_0?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
        username: root
        password: root
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/xxx_dev_1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
        username: root
        password: root
    sharding:
      tables:
        output_base_invoice_history:
          name: tableName1
          database-strategy:  #分库策略
            inline:
              sharding-column: dept_id #分片列
              algorithm-expression: ds$->{dept_id % 2} # 计算数据分到哪个数据库
          actualDataNodes: ds$->{0..1}.tableName1_$->{0..1} # 映射到 ds0 和 ds1 数据源
          table-strategy:  #分表策略
            inline:
              algorithm-expression: tableName1_$->{dept_id % 2}
              sharding-column: dept_id

        output_base_history_invoice_items:
          name: tableName2
          database-strategy: #分库策略
            inline:
              sharding-column: dept_id #分片列
              algorithm-expression: ds$->{dept_id % 2} # 计算数据分到哪个数据库
          actualDataNodes: ds$->{0..1}.tableName2_$->{0..1} # 映射到 ds0 和 ds1 数据源
          table-strategy: #分表策略
            inline:
              algorithm-expression: tableName2_$->{dept_id % 2}
              sharding-column: dept_id
      props:
        sql:
          show: true

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      ds0:
        enabled: true
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/xxx_dev_0?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
        username: root
        password: root
      ds1:
        enabled: true
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/xxx_dev_1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
        username: root
        password: root

(2)在ruoyi-framework工程下 修改DruidConfig类,添加Sharding的动态数据源支持:

首先,添加SHARDING的枚举

/**
 * 数据源
 *
 * @author ruoyi
 */
public enum DataSourceType {
    /**
     * 主库
     */
    MASTER,

    /**
     * 从库
     */
    SLAVE,
    /**
     * 分库分表
     */
    SHARDING
}

其次,添加sharding规则到动态数据源

   @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource(DataSource masterDataSource)
    {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
        setDataSource(targetDataSources, DataSourceType.SHARDING.name(), "shardingDataSource");
        return new DynamicDataSource(masterDataSource, targetDataSources);
    }

之后,新建ShardingJdbc的配置类

/**
 * sharding 配置信息
 *
 * @author yanjun.hou
 * <p>
 * 用法:@DataSource(DataSourceType.SHARDING)
 * 在对应需要分表操作的service方法上加上注解
 * 如整个service都需要分表操作, 可直接将该注解加载类上
 */
@Configuration
public class ShardingDataSourceConfig {


    @Value("${spring.shardingsphere.sharding.tables.tableName1.name}")
    private String historyTable;
    @Value("${spring.shardingsphere.sharding.tables.tableName1.actualDataNodes}")
    private String historyTableActualDataNodes;
    @Value("${spring.shardingsphere.sharding.tables.tableName1.database-strategy.inline.sharding-column}")
    private String historyDbShardingColumn;
    @Value("${spring.shardingsphere.sharding.tables.tableName1.database-strategy.inline.algorithm-expression}")
    private String historyDbAlgorithmExpression;

    @Value("${spring.shardingsphere.sharding.tables.tableName1.table-strategy.inline.sharding-column}")
    private String historyTableShardingColumn;
    @Value("${spring.shardingsphere.sharding.tables.tableName1.table-strategy.inline.algorithm-expression}")
    private String historyTableAlgorithmExpression;


    @Value("${spring.shardingsphere.sharding.tables.tableName2.name}")
    private String historyItemsTable;
    @Value("${spring.shardingsphere.sharding.tables.tableName2.actualDataNodes}")
    private String historyItemsTableActualDataNodes;
    @Value("${spring.shardingsphere.sharding.tables.tableName2.database-strategy.inline.sharding-column}")
    private String historyItemsDbShardingColumn;
    @Value("${spring.shardingsphere.sharding.tables.tableName2.database-strategy.inline.algorithm-expression}")
    private String historyItemsDbAlgorithmExpression;

    @Value("${spring.shardingsphere.sharding.tables.tableName2.table-strategy.inline.sharding-column}")
    private String historyItemsTableShardingColumn;
    @Value("${spring.shardingsphere.sharding.tables.tableName2.table-strategy.inline.algorithm-expression}")
    private String historyItemsTableAlgorithmExpression;

    @Bean
    @ConfigurationProperties("spring.datasource.druid.ds0")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.ds0", name = "enabled", havingValue = "true")
    public DataSource order1DataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.ds1")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.ds1", name = "enabled", havingValue = "true")
    public DataSource order2DataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean(name = "shardingDataSource")
    @ConditionalOnProperty(prefix = "spring.shardingsphere", name = "enabled", havingValue = "true")
    public DataSource shardingDataSource(@Qualifier("order1DataSource") DataSource order1DataSource, @Qualifier("order2DataSource") DataSource order2DataSource) throws SQLException {
        Map<String, DataSource> dataSourceMap = new HashMap<>();
        dataSourceMap.put("ds0", order1DataSource);
        dataSourceMap.put("ds1", order2DataSource);
 
        // 表规则配置
        TableRuleConfiguration invoiceHistory = new TableRuleConfiguration(historyTable, historyTableActualDataNodes);
        // 分库策略
        invoiceHistory.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration(historyDbShardingColumn, historyDbAlgorithmExpression));
        // 分表策略
        invoiceHistory.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration(historyTableShardingColumn, historyTableAlgorithmExpression));

 
        // 表规则配置
        TableRuleConfiguration invoiceHistoryItems = new TableRuleConfiguration(historyItemsTable, historyItemsTableActualDataNodes);
        // 分库策略
        invoiceHistoryItems.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration(historyItemsDbShardingColumn, historyItemsDbAlgorithmExpression));
        // 分表策略
        invoiceHistoryItems.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration(historyItemsTableShardingColumn, historyItemsTableAlgorithmExpression));

        // 分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        Collection<TableRuleConfiguration> tableRuleConfigs = shardingRuleConfig.getTableRuleConfigs();
        tableRuleConfigs.add(invoiceHistory);
        tableRuleConfigs.add(invoiceHistoryItems);
        // 获取数据源对象
        DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, getProperties());
        return dataSource;
    }

    /**
     * 系统参数配置
     */
    private Properties getProperties() {
        Properties shardingProperties = new Properties();
        shardingProperties.put("sql.show", true);
        return shardingProperties;
    }
}

最后,用法

首先,需要在application.yml中添加激活配置

active: dev,sharding

其次,在对应业务Mapper或者ServiceImpl 或者对应的方法上 添加 @DataSource(DataSourceType.SHARDING) 即可。

第一种
@DataSource(DataSourceType.SHARDING)
public interface xxxMapper {}

第二种
@DataSource(DataSourceType.SHARDING)
public class xxxServiceImpl {}

第三种
@Override
@DataSource(DataSourceType.SHARDING)
 public XXX xxx() {
     return xxx;
 }

其中,第一种和第二种都表示当前类下的所有方法都默认按照分库分表的规则进行。

重点说明:由于ShardingJdbc不支持修改分片键,所以在mapper的xml更新语句中,需要排除掉分片键的更新。

说明:如果是在老项目上进行分库分表,那么一般会涉及到数据的迁移。

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
课程目标快速的掌握读写分离+分表的实战,即插即用适用人群IT从业人员,开发人员,Java从业者,互联网从业者,性能调优人群课程简介ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。它由Sharding-JDBCSharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。Sharding-JDBCSharding-JDBCSharding-Sphere的第一个产品,也是Sharding-Sphere的前身,是当当网开源的一个产品。定位为轻量级的Java框架,在JavaJDBC层提供额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。Sharding-JDBC可以通过Java,YAML,Spring命名空间和Spring Boot Starter四种方式配置,开发者可根据场景选择适合的配置方式。课程特色 本章节以尽量短的时间,为使用者提供最简单的ShardingSphere的快速入门。课程说明该课程属于系列课程,分为读写分离,分库不分表,不分库分表分库分表,读写分离+分库分表共5个回合。本课程属于其中一个回合,请各位小哥哥们注意,课程的标题哦~
好的,下面是使用Ruoyi框架实现Sharding-JDBC分表的步骤: 1. 引入Sharding-JDBC依赖 在pom.xml文件中添加Sharding-JDBC的依赖: ```xml <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>4.1.1</version> </dependency> ``` 2. 配置数据源 在application.yml中配置数据源信息,如下所示: ```yaml spring: datasource: # 主库 master: url: jdbc:mysql://localhost:3306/db_master?serverTimezone=UTC&useSSL=false&characterEncoding=utf-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 从库 slave: url: jdbc:mysql://localhost:3306/db_slave?serverTimezone=UTC&useSSL=false&characterEncoding=utf-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver shardingsphere: datasource: names: master,slave # 配置主从库 master-slave-rules: ms: master-data-source-name: master slave-data-source-names: slave load-balance-algorithm-type: round_robin # 配置数据分片规则 sharding: tables: user_info: # 分库键 database-strategy: inline: sharding-column: user_id algorithm-expression: ds${user_id % 2} # 分表键 table-strategy: inline: sharding-column: order_id algorithm-expression: t_order_${order_id % 2} actual-data-nodes: master.user_info_$->{0..1} key-generator: column: id type: SNOWFLAKE ``` 3. 创建数据表 创建两个数据库db_master和db_slave,每个数据库中创建user_info表,表结构如下: ```sql CREATE TABLE `user_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `order_id` bigint(20) NOT NULL COMMENT '订单ID', `name` varchar(50) NOT NULL COMMENT '姓名', `age` int(11) NOT NULL COMMENT '年龄', `address` varchar(200) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表'; ``` 4. 创建Mapper接口 在Ruoyi框架中,通常使用MyBatis-Plus进行数据库操作,因此需要创建对应的Mapper接口,如下所示: ```java public interface UserInfoMapper extends BaseMapper<UserInfo> { } ``` 5. 测试分库分表 在代码中使用Sharding-JDBC进行数据库操作,如下所示: ```java @Service public class UserServiceImpl implements IUserService { @Autowired private UserInfoMapper userInfoMapper; @Override public void addUser(UserInfo userInfo) { userInfoMapper.insert(userInfo); } @Override public List<UserInfo> getUserList() { return userInfoMapper.selectList(null); } } ``` 以上就是使用Ruoyi框架实现Sharding-JDBC分表的步骤。需要注意的是,Sharding-JDBC支持使用MyBatis-Plus的自动填充功能,因此需要手动设置分表键的值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

还算善良_

如果对你的工作有所帮助,拜托啦

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

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

打赏作者

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

抵扣说明:

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

余额充值