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 领域为我们的日常生活提供了许多不可或缺的技术服务。无论你是初学者…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
