gorm.io/sharding:改造,当查询条件中不包含分表键时,从自定义方法中获取对应的表进行查询
项目背景
这篇文章是一种特殊的情形——当查询条件中不包含分表键时,从自定义方法中获取对应的表进行查询。实际项目中并不建议这种用法。
当然,这里只是提供一种思路。这篇文章也是这个系列中的第三篇文章。前两篇文章《基于gorm.io/sharding分表中间件使用案例》、《gorm.io/sharding使用中遗留问题探究:Error 1062 (23000): Duplicate entry ‘2‘ for key ‘orders_2025.PRIMARY》有兴趣的看官可以移步过去看看。
解决方案
我们重点关注回调函数注册的逻辑,这段回调函数的注册逻辑中,我们重点关注查询的回调函数注册,实际上这几个逻辑是一致的。
s.Callback().Query().Before("*").Register("gorm:sharding", s.switchConn)这行代码在查询(Query)操作的所有内置回调之前注册了一个名为gorm:sharding
的自定义回调,该回调执行s.switchConn
方法。这意味着在每次执行查询操作之前,都会先调用s.switchConn
方法来根据分片规则选择或切换数据库连接。
func (s *Sharding) registerCallbacks(db *gorm.DB) {s.Callback().Create().Before("*").Register("gorm:sharding", s.switchConn)s.Callback().Query().Before("*").Register("gorm:sharding", s.switchConn)s.Callback().Update().Before("*").Register("gorm:sharding", s.switchConn)s.Callback().Delete().Before("*").Register("gorm:sharding", s.switchConn)s.Callback().Row().Before("*").Register("gorm:sharding", s.switchConn)s.Callback().Raw().Before("*").Register("gorm:sharding", s.switchConn)
}
所以,我们的目标就是修改这个自定义回调方法switchConn。
func (s *Sharding) switchConn(db *gorm.DB) {// Support ignore sharding in some case, like:// When DoubleWrite is enabled, we need to query database schema// information by table name during the migration.if _, ok := db.Get(ShardingIgnoreStoreKey); !ok {s.mutex.Lock()if db.Statement.ConnPool != nil {s.ConnPool = &ConnPool{ConnPool: db.Statement.ConnPool, sharding: s}db.Statement.ConnPool = s.ConnPool}s.mutex.Unlock()}// 获取查询语句的上下文信息ctx := db.Statement.Context// 检查查询中是否包含分表键(这里需要根据实际情况实现具体的检查逻辑)containsShardKey := true// 从上下文中获取查询条件中是否包含分表键if ctx.Value("no_sharding") != nil {containsShardKey = false}// 如果不包含分表键,则使用自定义函数获取表名if !containsShardKey && s._config.TableResolver != nil {tableName := s._config.TableResolver(ctx)if tableName != "" {// 设置查询的表名db.Statement.Table = tableName}}
}
因此,我们还需要在config中增加一个传自定义的获取表明的方法。
// Config specifies the configuration for sharding.
type Config struct {// When DoubleWrite enabled, data will double write to both main table and sharding table.DoubleWrite bool// ShardingKey specifies the table column you want to used for sharding the table rows.// For example, for a product order table, you may want to split the rows by `user_id`.ShardingKey string// NumberOfShards specifies how many tables you want to sharding.NumberOfShards uint// 当查询中需要指定表时,使用该函数来解析表名TableResolver func(context.Context) string// tableFormat specifies the sharding table suffix format.tableFormat string// ShardingAlgorithm specifies a function to generate the sharding// table's suffix by the column value.// For example, this function implements a mod sharding algorithm.//// func(value any) (suffix string, err error) {// if uid, ok := value.(int64);ok {// return fmt.Sprintf("_%02d", user_id % 64), nil// }// return "", errors.New("invalid user_id")// }ShardingAlgorithm func(columnValue any) (suffix string, err error)// ShardingSuffixs specifies a function to generate all table's suffix.// Used to support Migrator and generate PrimaryKey.// For example, this function get a mod all sharding suffixs.//// func () (suffixs []string) {// numberOfShards := 5// for i := 0; i < numberOfShards; i++ {// suffixs = append(suffixs, fmt.Sprintf("_%02d", i%numberOfShards))// }// return// }ShardingSuffixs func() (suffixs []string)// ShardingAlgorithmByPrimaryKey specifies a function to generate the sharding// table's suffix by the primary key. Used when no sharding key specified.// For example, this function use the Snowflake library to generate the suffix.//// func(id int64) (suffix string) {// return fmt.Sprintf("_%02d", snowflake.ParseInt64(id).Node())// }ShardingAlgorithmByPrimaryKey func(id int64) (suffix string)// PrimaryKeyGenerator specifies the primary key generate algorithm.// Used only when insert and the record does not contains an id field.// Options are PKSnowflake, PKPGSequence and PKCustom.// When use PKCustom, you should also specify PrimaryKeyGeneratorFn.PrimaryKeyGenerator int// PrimaryKeyGeneratorFn specifies a function to generate the primary key.// When use auto-increment like generator, the tableIdx argument could ignored.// For example, this function use the Snowflake library to generate the primary key.// If you don't want to auto-fill the `id` or use a primary key that isn't called `id`, just return 0.//// func(tableIdx int64) int64 {// return nodes[tableIdx].Generate().Int64()// }PrimaryKeyGeneratorFn func(tableIdx int64) int64
}
改造的工作就此完成,当然,如果实际要使用这种方式,上述还有诸多需要优化的地方,因为,只是用于说明解决方案的思路,所以,上述改造并不是最优解。
接下来,我们看一下使用案例。
测试案例
直接上代码。
说明:关于order的定义,建表的逻辑,测试数据插入等在这个系列中的另外两篇文章中有定义。
package testimport ("context""fmt""testing""time""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/sharding"
)func customTableResolver(ctx context.Context) string {if ctx.Value("year") != nil {return fmt.Sprintf("orders_%d", ctx.Value("year"))}return ""
}// Test_Gorm_Sharding 用于测试 Gorm Sharding 插件
func Test_Gorm_Sharding2(t *testing.T) {// 连接到 MySQL 数据库dsn := "user:password@tcp(ip:port)/sharding_db2?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.New(mysql.Config{DSN: dsn,}), &gorm.Config{})if err != nil {panic("failed to connect database")}globalDB = db// 配置 Gorm Sharding 中间件,使用自定义的分片算法middleware := sharding.Register(sharding.Config{ShardingKey: "order_id",TableResolver: customTableResolver, // 使用自定义的表解析器ShardingAlgorithm: customShardingAlgorithm, // 使用自定义的分片算法PrimaryKeyGenerator: sharding.PKMySQLSequence,}, "orders") // 逻辑表名为 "orders"db.Use(middleware)// 没有分表键的查询ctx := context.Background()ctx = context.WithValue(ctx, "year", 2024)ctx = context.WithValue(ctx, "no_sharding", true)err = db.WithContext(ctx).Model(&Order{}).Where("product_id=?", 102).Find(&orders).Errorif err != nil {fmt.Println("Error querying orders:", err)}fmt.Printf("no sharding key Selected orders: %#v\n", orders)
}
相关文章:
gorm.io/sharding:改造,当查询条件中不包含分表键时,从自定义方法中获取对应的表进行查询
项目背景 这篇文章是一种特殊的情形——当查询条件中不包含分表键时,从自定义方法中获取对应的表进行查询。实际项目中并不建议这种用法。 当然,这里只是提供一种思路。这篇文章也是这个系列中的第三篇文章。前两篇文章《基于gorm.io/sharding分表中间…...

【CSS】变量的声明与使用
原生变量root 伪类 原生变量 CSS中我们可以统一设置变量方便页面维护。变量声明的时候,自定义样式变量名之前加上两根连词线 " – " 即可,使用 var() 来引用。声明的变量是有作用域的 ( 比如是在html中声明的变量,那么该变量在html…...

【数学分析笔记】第3章第4节闭区间上的连续函数(1)
3. 函数极限与连续函数 3.4 闭区间上的连续函数 3.4.1 有界性定理 【定理3.4.1】 f ( x ) f(x) f(x)在闭区间 [ a , b ] [a,b] [a,b]上连续,则 f ( x ) f(x) f(x)在闭区间 [ a , b ] [a,b] [a,b]上有界。 【证】用反证法,假设 f ( x ) f(x) f(x)在 [ …...
Mybatis中sql数组为空判断
一、Mybatis xml中的sql通过if语句判定是否为空 <if test"arrays ! null"> </if>上述示例只能判断arrays数组不为null,那如果是个空数组呢 二、Mybatis xml中的sql通过if语句判定数组非空数组 <if test"arrays ! null and arrays.l…...

12.第二阶段x86游戏实战2-CE找基地址
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要…...
笔记整理—内核!启动!—linux应用编程、网络编程部分(3)文件共享与标准IO
文件共享是指同一个文件被多个独立的读写进行操作。同一个文件为同一个inode,同一个pathname也就是同一个静态文件。同时进行操作,打开一个文件未关闭又被另一个操作打开。文件共享的方式可以实现高效的大文件读写。 文件共享的三种方式:①同…...

plt常用函数介绍一
目录 前言plt.figure()plt.subplot()plt.subplots()plt.xticks()plt.xlim() 前言 Matplotlib是Python中的一个库,它是数字的-NumPy库的数学扩展。 Pyplot是Matplotlib模块的基于状态的接口。在Pyplot中可以使用各种图,例如线图,轮廓图&#…...

基于ExtendSim的 电子制造 仿真模型
说明: 此模型表示电路板制造设施。该过程有4个步骤: *焊料制备 *组件放置 *烤箱 *检查 详情: *烤箱的容量为10张卡,但如果烤箱循环开始时仅能处理5张卡,则最多只能处理5张。 *如果检查员发现问题,他们将修理…...

BGP 路由反射器
转载:BGP 路由反射器 / 实验介绍: / 原理概述 缺省情况下,路由器从它的一个 IBGP 对等体那里接收到的路由条目不会被该路由器再传递给其他IBGP对等体,这个原则称为BGP水平分割 原则,该原则的根本作用是防止 AS 内部的 BGP 路由…...

CSRF高级防御绕过
1)回顾low级别做过csrf页面的密码重置,重复之前的操作,我们发现级别调整中级之后,报错如下 2)检查源码 进入dvwa源码,查找到checktoken: 3)在dvwa-csrf页面上,抓包 http…...

MySQL安装文档-Windows
文章目录 MySQL安装1. 安装2. 配置 MySQL安装 1. 安装 1). 双击官方下来的安装包文件 2). 根据安装提示进行安装 安装MySQL的相关组件,这个过程可能需要耗时几分钟,耐心等待。 输入MySQL中root用户的密码,一定记得记住该密码 2. 配置 安装好MySQL之后…...

html TAB、table生成
1. 代码 <!DOCTYPE html> <head> <meta charset"UTF-8"> <title>Dynamic Tabs with Table Data</title> <style> /* 简单的样式 */ .tab-content { display: none; border: 10px solid #ccc; padding: 30px; mar…...
2024!再见前端!
各位朋友大家晚上好,夜深了,睡不着,想想还是写一篇文章和大家说再见吧! 自2014年入行前端以来,满打满算差不多整整十年了,这十年可以说是见证了中国整个互联网的起飞到全盛时期。这期间经历了电商、金融、…...

【源码+文档+调试讲解】人事管理系统设计与实现Python
摘 要 人事管理系统的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品,体验高科技时代带给人们的方便,同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓,iOS相比较起来ÿ…...

基于注意力机制的图表示学习:GRAPH-BERT模型
人工智能咨询培训老师叶梓 转载标明出处 图神经网络(GNNs)在处理图结构数据方面取得了显著的进展,但现有模型在深层结构中存在性能问题,如“悬挂动画问题”和“过平滑问题”。而且图数据内在的相互连接特性限制了大规模图输入的并…...

linux服务器安装原生的php环境
在CentOS上安装原生的PHP环境相对简单。下面是一个详细的步骤指南,适用于CentOS 7及更高版本。 ### 第一步:更新系统 首先,确保你的系统是最新的: sudo yum update -y ### 第二步:安装EPEL和Remi仓库 1. **安装EP…...

数电学习基础(逻辑门电路+)
1.逻辑门电路 1.1逻辑门电路的简介 1.1.1各种逻辑门电路的简介 基本概念 (1)实现基本逻辑运算和常用逻辑运算的电路称为逻辑门电路,简称门电路。逻辑门电路是组成各种数字电路的基本单元电路。将构成门电路的元器件制作一块半导体芯片上再…...
【艾思科蓝】Spring Boot实战:零基础打造你的Web应用新纪元
第七届人文教育与社会科学国际学术会议(ICHESS 2024)_艾思科蓝_学术一站式服务平台 更多学术会议请看:https://ais.cn/u/nuyAF3 目录 一、Spring Boot简介 1.1 Spring Boot的诞生背景 1.2 Spring Boot的核心特性 二、搭建开发环境 2.1…...

C++ 二叉树
1. 二叉搜索树 1.1 二叉搜索树概念 二叉搜索树又称二叉排序树,他或者是一棵空树,或者是具有以下性质的二叉树: ①若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 ②若它的右子树不为空,则右子树上所有节…...
初探IT世界:从基础到未来
初探IT世界:从基础到未来 1. 引言 随着科技的不断发展,IT(信息技术)已经成为全球经济的支柱之一。从软件开发、网络安全到数据分析和人工智能,IT 领域为我们的日常生活提供了许多不可或缺的技术服务。无论你是初学者…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...