ShardingSphere-JDBC —— 整合 mybatis-plus,调用批量方法执行更新操作扫所有分表问题

文章目录

  • 过程及问题描述
  • 原因及方案

记录下 ShardingSphere 整合 mybatis-plus 进行批量更新时扫所有分表问题的原因及解决方案。ShardingSphere 整合 mybatis-plus 与整合 mybatis 流程是一样的,一个是导入 mybatis 包,一个是导入 mybatis-plus 包,在 ShardingSphere-JDBC —— 数据分片详细讲解 介绍了 ShardingSphere 分布分表及整合 mybatis 的使用示例,这里就不在赘述整合使用过程了。

过程及问题描述

在使用 ShardingSphere 整合 mybatis-plus 并调用 saveOrUpdateBatch() 批量插入或更新方法,发现数据批量插入时,ShardingSphere 的分片规则会根据分片键的值将数据正确地分散到各个分片表中;而数据批量更新时,会扫描所有分表进行更新。这是什么原因呢?

首先看我是如何使用的。

  1. 数据表的设计,表字段如下,id 自增主键、text 唯一索引。这里建 32 张分表,test_table_0 … test_table_31

    CREATE TABLE `test_table` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',`text` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '文本内容',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `text` (`encrypt_text`) USING BTREE,KEY `idx_user_id` (`user_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='文本';
    
  2. ShardingSphere 相关配置,详细配置不再降速,就看看数据库表分片配置。这里设置 text 字段作为分片键。

    @Bean(name = "textTableTableRuleConfig")
    public TableRuleConfiguration textTableTableRuleConfig() {String tableName = "test_table";String actualDataNodes = "dataSource.test_table_${0..31}";// 分片键String shardingColumns = "text";// 表规则配置TableRuleConfiguration configuration = new TableRuleConfiguration();configuration.setLogicTable(tableName);	// 设置逻辑表名configuration.setActualDataNodes(actualDataNodes); // 设置实际分表节点// 分片策略,UserEncryptTextTableAlgorithm 为自定义分片算法ShardingStrategyConfiguration tableShardingStrategyConfig = new StandardShardingStrategyConfiguration(shardingColumns, new UserEncryptTextTableAlgorithm());// 数据库没分库,不用分片策略;数据表分表,设置分片策略。configuration.setDatabaseShardingStrategyConfig(new NoneShardingStrategyConfiguration());configuration.setTableShardingStrategyConfig(tableShardingStrategyConfig);return configuration;
    }
    

    分片算法。使用 PreciseShardingAlgorithm,是 ShardingSphere 提供的精确分片算法接口,用于处理单一分片键的分片规则。

    @Configuration
    public class UserEncryptTextTableAlgorithm implements PreciseShardingAlgorithm<String> {/*** availableTargetNames:可用的分片目标名称集合,即分片规则所涉及的所有分片表的集合。* shardingValue:PreciseShardingValue 对象,表示单一分片键的值。*/@Overridepublic String doSharding(Collection<String> collection, PreciseShardingValue<String> shardingValue) {StringBuffer tableName = new StringBuffer();// shardingValue.getValue():分片键的值String tableSuffix = String.valueOf(Math.abs(shardingValue.getValue().hashCode()) % 32);tableName.append(shardingValue.getLogicTableName()).append("_").append(tableSuffix);return tableName.toString();}
    }
    
  3. 业务代码操作数据表,这里调用 mybatis-plus 的批量方法。

    // mybatis-plus 操作数据库服务类
    @Autowired
    private ITestTableService iTestTableService;public static void main(String[] args) {List<TestTable> testTableList = new ArrayList<>();TestTable updateInfo· = new TestTable();updateInfo1·.setText("test1");updateInfo1·.setId(1);updateInfo1·.setCreateTime(new Date());testTableList.add(updateInfo1);TestTable updateInfo1 = new TestTable();updateInfo2.setText("test2");updateInfo2.setId(2);updateInfo2.setCreateTime(new Date());testTableList.add(updateInfo2);iTestTableService.saveOrUpdateBatch(testTableList);
    }
    
  4. 运行结果

    配置 ShardingSphere 数据源时开启sql打印,方便在控制台查看输出的sql语句。

    Properties prop = new Properties();
    prop.setProperty(ShardingPropertiesConstant.SQL_SHOW.getKey(), true);
    

    运行条件:假设 updateInfo1 的数据已存在与表中,updateInfo2 的数据在表中不存在。在进行 iTestTableService.saveOrUpdateBatch(testTableList); 运行后。

    insert 语句只打印了一次。
    INSERT INTO test_table_10(id, text, create_time, update_time) VALUES (?,?, ?, ?);

    update 语句只打印了32次。
    UPDATE table_name_0 SET id = ?, text= ?, create_time = ?, update_time = ? WHERE id = ?;
    UPDATE table_name_1 SET id = ?, text= ?, create_time = ?, update_time = ? WHERE id = ?;

    UPDATE table_name_32 SET id = ?, text= ?, create_time = ?, update_time = ? WHERE id = ?;

    看表中数据,32 张表中只有一张表中插入了 updateInfo2 的数据,说明只执行了一次 insert 操作,而且按分片规则落到指定的分表中;而 updateInfo1 在表中的数据已被修改了,说明更新了,是否是只执行了一次 update 操作呢?继续分析。

  5. 分析及结论

    那打印了 32 次 update 语句,是否执行了 32 次 update 操作呢?首先看打印的 sql,saveOrUpdateBatch() 批量 update 操作打印的sql,where 条件是 id = ?,那我在另外一张不存在 updateInfo1 数据的表中插入一条数据,其 id 也等于1,再执行一遍更新操作,发现两张表的 updateInfo1 数据都进行了更新,说明确实执行了 32 次 update 操作。

    查看打印的 update sql 语句,可以看出 mybatis-plus 的 saveOrUpdateBatch() 操作批量更新时,是以 id 主键作为 where 条件来索引更新,而 id 主键又不是分片键,分片规则失效,所以每一次 update 都会扫所有分表。而对于 insert 操作,可以理解插入的字段包含 id 主键和 text 唯一索引,且 text 作为分片键,所以插入时会解析到包含分片键 text,会先进行分表定位到具体表,再插入。

原因及方案

针对 update 操作的问题:

  1. 于是,我再使用 mybatis-plus 的 saveOrUpdate(T entity); 方法与 saveOrUpdate(T entity, Wrapper updateWrapper); 方法单独对 updateInfo1 进行更新操作。(mybatis-plus 现象)

    iTestTableService.saveOrUpdate(updateInfo1);
    与
    iTestTableService.saveOrUpdate(updateInfo1, Wrappers.<UserEncryptText>lambdaUpdate().eq(UserEncryptText::getText, updateInfo.getText()));
    

    这两种更新操作的结果为:不带条件的还是扫描所有分表,带条件能定位到具体分表进行更新。说明在进行 saveOrUpdate(updateInfo1) 操作更新时,mybatis-plus 默认是使用主键索引作为 where 条件进行索引的;使用 saveOrUpdate(updateInfo1, Wrappers) 操作更新时才会使用指定的 where 条件。

  2. 其次,我更改分片键,使用多字段分片键的分片策略,id 与 text 字段都作为分片键。(ShardingSphere 现象)

    String shardingColumns = "id,text";
    ShardingStrategyConfiguration tableShardingStrategyConfig = new ComplexShardingStrategyConfiguration(shardingColumns, new UserEncryptTextTableAlgorithm());
    

    分片算法。使用 ComplexKeysShardingAlgorithm,是 ShardingSphere 中用于处理复合分片键的分片算法接口。该接口定义了根据多个分片键进行分片的方法。这里简单处理,同时存在 id、text 或 text 都映射到 text 作为分片键,只有 id 分片键就默认分到0表。

    public class UserEncryptTextTableAlgorithm implements ComplexKeysShardingAlgorithm {@Overridepublic Collection<String> doSharding(Collection<String> collection, Collection<ShardingValue> collection1) {List<String> list = new ArrayList<>();Optional<ShardingValue> optional = collection1.stream().filter(x -> StringUtils.equals(x.getColumnName(), "text")).findFirst();if (!optional.isPresent()){StringBuffer tableName = new StringBuffer();tableName.append(shardingValue.getLogicTableName()).append("_").append(0);list.add(tableName.toString());return list;}ListShardingValue shardingValue = (ListShardingValue)optional.get();Collection values = shardingValue.getValues();values.forEach(value -> {StringBuffer tableName = new StringBuffer();String tableSuffix = String.valueOf(Math.abs(shardingValue.getValue().hashCode()) % 32);tableName.append(shardingValue.getLogicTableName()).append("_").append(tableSuffix);list.add(tableName.toString());});return list;}
    }
    

    1、当条件为 where id = ? 时,分片算法中的入参 collection1 集合中只有 id 分片键对象,只能使用 id 分片键进行分片算法,这里直接操作了 0 表;
    2、当条件为 where text = ? 时,分片算法中的入参 collection1 集合中只有 text 分片键对象,使用 text 分片键进行分片算法,锁定操作某一个分表;
    3、当条件为 where id = ? AND text = ? 时,分片算法中的入参 collection1 集合中有 id 和 text 分片键对象,使用 text 分片键进行分片算法,锁定操作某一个分表;
    4、当条件为 where create_time = ? 等其他非分片键时,直接跳过分片算法,不会调用到分片算法,然后会扫描所有分表;

    所以在进行 update 操作时,可以理解会先解析 where 条件,判断包含了哪些分片键,并以这些分片键按照分片算法逻辑进行分表定位到具体表,再插入;若一个分片键都不包含,分片算法失效,直接扫所有分表操作。

最终如何进行批量更新操作:

  1. 方案一:轮询使用带条件的更新操作,如:saveOrUpdate(updateInfo1, Wrappers) 、update(updateInfo1, Wrappers)
  2. 方案二:若要使用 saveOrUpdateBatch() 方法,将 id 设置为分片键,并且要保证 id 分片键与 text 分片键进行分片算法时能得到相同的分表。(上面示例并没有实现,只是为了简单演示。)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/45796.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

canvas快速入门(一)canvas的基础使用

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1. canvas的两种创建方式及优劣 2. canvas宽高设置及注意事项 3. 简单测例 项目结构&#xff1a; 源码&#xff1a; index.html <!DOCTYPE html> <html lang"en"> <head><meta charset…

7.7 CyclicBarrier

CyclicBarrier 循环栅栏&#xff0c;用来进行线程协作&#xff0c;等待线程满足某个计数。构造时设置【计数个数】。每个线程执行到某个需要“同步”的时刻调用 await() 方法进行等待&#xff0c;当等待的线程数满足【计数个数】时&#xff0c;继续执行。 Slf4j(topic "…

MySQL学习记录 —— 십구 命令执行

文章目录 1、mysql客户端命令2、从.sql文件执行SQL语句 1、mysql客户端命令 使用mysql时&#xff0c;命令行要以分号或者\g&#xff0c;\G来结束。 mysql客户端的很多命令可以在之前的mysql博客中查看。另外的用help或\h命令来查看。本篇写一些之前没有提到过的。 命令结束符…

先天睡功-守一老师

描述 守一老师&#xff0c;一个富有才华的老师&#xff01; 对于大家的学习有不可多得的帮助。 内容 目前主要的内容以睡觉为主&#xff0c;对于学习睡睡觉有比较大的帮助&#xff01; 但是网络上面错综复杂&#xff0c;很多老旧的版本影响学习&#xff01; 而这里我整理了…

安全防御实验2

一、实验拓扑 二、实验要求 办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换)分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的http服务器多出口环境基于带宽比例进行选路&#xff0c;但是&#xff0c;办公区…

数据建设实践之大数平台(六)安装spark

安装spark 上传安装包到/opt/software目录并解压 [bigdatanode101 software]$ tar -xvf spark-3.3.1-bin-hadoop3.tgz -C /opt/services/ [bigdatanode101 software]$ tar -xvf spark-3.3.1-bin-without-hadoop.tgz -C /opt/services/ 重命名文件 [bigdatanode101 servic…

OZON夏季热卖产品有哪些,OZON夏季热卖新品

OZON平台在夏季的热卖产品种类繁多&#xff0c;涵盖了多个领域&#xff0c;主要包括但不限于以下几个方面&#xff0c;接下来看看OZON夏季热卖产品有哪些&#xff0c;OZON夏季热卖新品&#xff01;Top1 运动套装 Костюм спортивный Victorias Secret 商品id…

c++课后作业

把字符串转换为整数 int main() {char pn[21];cout << "请输入一个由数字组成的字符串&#xff1a; ";cin >> pn;int last 0;int res[10];int j strlen(pn);int idx 2;cout << "请选择&#xff08;2-二进制&#xff0c;10-十进制&#xf…

【C++】C++入门实战教程(打造属于自己的C++知识库)

目录 目录 写在前面 1.C学习路线 2.本教程框架介绍 一.C基础部分 1.程序编码规范 2.程序运行与编译 3.关键字 4.常用数据类型 5.运算符相关 二.C进阶部分 1.面向对象编程 2.函数编程 3.模板编程 4.多线程与并发 5.STL介绍及使用 6.内存模型与优化 三.C实战部…

C++常用算法的简单总结

1、遍历算法 for_each(iterator beg, iterator end, func) :遍历容器 transform(iterator beg1, iterator end1, iterator beg2, _func): func可以直接搬运数据&#xff0c;也可以数据加减乘除之后搬运 2、查找算法 find(iterator beg, iterator end, 需要查找的数据) 查找元素…

美国视觉AI解决方案公司Hayden AI完成9000万美元C轮融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于美国加利福尼亚州旧金山弗朗西斯科专门为智慧城市提供视觉AI解决方案的Hayden AI&#xff0c;近期宣布已完成9000万美元C轮融资。 本轮融资由The Rise Fund领投&#xff0c;Drawdown Fun…

为什么go语言里从前端接收到的参数是数字28546.123456,但是不能使用float32只能使用float64呢?

在 Go 语言中&#xff0c;当从前端&#xff08;例如通过 HTTP 请求&#xff09;接收数据时&#xff0c;这些数据通常以字符串的形式到达后端。然后&#xff0c;后端需要将这些字符串解析或转换为适当的类型&#xff0c;比如 float32 或 float64。 然而&#xff0c;如果发现你只…

股指期货存在的风险有哪些?

股指期货因其标的物的特殊性&#xff0c;其面临的风险类型十分复杂&#xff0c;主要面临的一般风险和特有风险如下&#xff1a; 一般风险 从风险是否可控的角度&#xff0c;可以划分为不可控风险和可控风险&#xff1b;从交易环节可分为代理风险、流动性风险、强制平仓风险&…

BUCK外围器件选型,输入电容,输出电容,电感,续流二极管

概述&#xff1a; 一般情况下&#xff0c;电源接口处会有大小不同的电容进行并联&#xff0c;大容量电容是为了防止自身产生干扰影响其他器件&#xff0c;所以叫去耦电容&#xff1b;小容量电容是为了其他高频干扰影响自身&#xff0c;所以叫旁路电容。当然这只是通常情况下。 …

将获取pose 服务拆分为两个服务

简单拆分 要将该代码拆分为两个服务&#xff0c;我们需要创建两个FastAPI应用。第一个服务&#xff08;我们可以称之为ImageCaptureService&#xff09;将负责捕获视频流中的图像&#xff0c;并将图像数据发送到第二个服务&#xff08;我们可以称之为PoseEstimationService&am…

深入剖析多个表left join on的执行步骤原理:实战案例解析与原理探讨

文章目录 文章导图前言初始化数据-建表两个表left jion多表-left jion on c.bidb.bid分析|执行步骤和结果理解 变形-修改c表数据变形1变形2 总结 多表-left jion on c.aida.aid分析执行步骤和结果理解 变形-修改c表数据变形1变形2 解答开头总结 Left join on系列文章测试一下你…

ubuntu添加软件快捷方式

# 该目录下存放着所有的快捷方式文件 cd /usr/share/applications/ # 创建一个快捷方式文件 sudo touch your_app_name.desktop # 编辑快捷方式文件 sudo gedit your_app_name.desktop把&#x1f447;的内容复制进your_app_name.desktop文件中&#xff0c;这是最简化版本 [Des…

数据结构第24节 二分查找

二分查找&#xff08;Binary Search&#xff09;&#xff0c;也被称为折半查找&#xff0c;是一种在有序数组中查找特定元素的高效算法。它的基本思想是将查找区间分为两部分&#xff0c;通过比较中间元素与目标值来决定下一步是在哪一半继续查找。 二分查找的步骤&#xff1a…

​Chrome 插件: GoFullPage 一键搞定全网页截图

在互联网时代&#xff0c;网页截图已成为我们日常工作和生活中不可或缺的部分。无论是保存重要信息、制作教程&#xff0c;还是分享有趣的内容&#xff0c;截图功能都显得尤为重要。然而&#xff0c;常规的截图工具往往只能截取当前屏幕的内容&#xff0c;对于长网页则显得力不…

做个简单的知识付费网站需要什么方式

网站是线上承载信息宣传的主要工具之一&#xff0c;也是企业公司发展的重要工具之一&#xff0c;除了固定信息呈现外&#xff0c;还有不少商家具备各种方式的干货输出能力&#xff0c;或者想以内容售卖获得一定营收。 如教培机构、自媒体、网校、知识生产者、领域达人等都具备…