讲师中心 微信公众号

工具推荐

视频效率加速
Laper
Laper

剧本策划到成片协作

Seko
Seko

AI短剧一键生成成片

剧云
剧云

中文短剧剧本制作平台

立刻MV
立刻MV

低成本歌曲 MV、视频生成

使用 Golang 构建可维护的 SQL 查询

夏静同学_4757

夏静同学_4757

发布时间:2024-08-16 09:48:49

|

1030人浏览过

|

来源于dev.to

转载

使用 golang 构建可维护的 sql 查询

任何使用 sql 查询的应用程序都可以受益于使用查询生成器来提高代码的可读性、可维护性和安全性。事实上,golang 中有许多不同的库可以做到这一点。在 vaunt,我们尝试了许多不同的选择,最后决定自己创建一个。最终,我们想要一些安全的东西,并提供变量替换来防止 sql 注入,同时仍然可读并且能够有条件语句。因此,我们创建了一个名为 tqla 的新库,并于去年年底发布并宣布。您可以在这篇文章中阅读更多相关信息。

在构建 tqla 之前,我们主要使用 squirrel 来构建 sql 查询逻辑——我们强烈推荐它。我们仍然在某些领域使用 squirrel,但已逐渐开始用 tqla 替换和实现新的查询构建逻辑。我们发现在许多实例中,tqla 提高了我们维护代码和修复使用其他语句生成器时遇到的问题的能力。

现实世界用例

在 vaunt,我们最近进行了从 cockroachdb 到 tidb 的数据库迁移。虽然 cockroachdb 高性能且可靠,但我们最终决定添加到我们的技术堆栈中以支持 olap 数据库。这样做的需要是支持我们对开源社区洞察产品的分析工作量。为了保持较小的技术足迹,我们决定继续使用 tidb 并利用该数据库的 htap 架构。 

cockroachdb 与 postgresql 很大程度上兼容,我们的许多 sql 查询都使用 postgresql 语法。要切换到 tidb,我们必须更改一些表并更新查询以使用 mysql 语法。在迁移过程中的一些位置,我们发现我们不正确地使用条件查询构建语句,并且缺乏适当的测试来发现语句生成不正确。

立即学习“go语言免费学习笔记(深入)”;

示范

在 squirrel 的自述文件中,有一个示例说明如何使用条件查询构建来更新带有可选过滤器的语句:

if len(q) > 0 {
    users = users.where("name like ?", fmt.sprint("%", q, "%"))
}

这是一个真实但简化的示例,说明我们如何更新其中一个查询以有条件连接表并添加可选过滤器:

psql := squirrel.statementbuilder.placeholderformat(squirrel.question)

statementbuilder := psql.select(`i.id`).
from("vaunt.installations i").
where(`entity_name = ?`, name)

if len(provider) > 0 {
    statementbuilder.where(`provider = ?`, provider)
}

if len(repo) > 0 {
    statementbuilder.join(`repositories as r on json_contains(i.repositories, concat('["', r.id, '"]'))`)
    statementbuilder.where(`r.name = ?`, repo)
}

你能发现代码的问题吗?如果没有,请不要担心——在我们运行测试之前,我们自己的代码审查也会忽略这一点。 

这里的问题是我们忘记使用构建器函数的结果更新语句构建器。例如,提供者条件过滤器应改为:

if len(provider) > 0 {
    statementbuilder = statementbuilder.where(`provider = ?`, provider)
}

这是一个相对简单的错误,通过足够的测试用例很容易发现,但由于它不是技术上无效的代码,因此可能需要一些时间才能立即意识到发生了什么。

此设置的另一个可读性问题是条件连接与初始 select 语句是分开的。我们可以重新组织构建器,将每个部分放在它应该去的地方,但这需要多次重复的条件语句检查,并且仍然会遇到一些可读性问题。

使用tqla

上面使用 squirrel 的演示已被重写,tqla 中的等效项如下所示:

win可用的mysql指令skill
win可用的mysql指令skill

安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。

下载
t, err := tqla.new(tqla.withplaceholder(tqla.question))
if err != nil {
    return nil, err
}

query, args, err := t.compile(`
    select i.id
    from vaunt.installations as i
    {{ if .repo }}
    join vaunt.repositories as r on json_contains(i.repositories, concat('["', r.id, '"]'), '$')
    {{ end }}
    where entity_name = {{ .name}}
    {{ if .provider }}
    and i.provider = {{ .provider }}
    {{ end }}
    {{ if .repo }}
    and r.name = {{ .repo }}
    {{ end }}
    `, data)
if err != nil {
    return nil, err
}

如您所见,tqla 的模板语法使得合并条件子句变得非常简单。 tqla 自动用指定的占位符替换我们设置的变量,并提供我们可以与 sql 驱动程序一起使用来执行语句的参数。

与 squirrel 类似,这种语句构建方法很容易测试,因为我们可以创建不同的数据对象集来传递给模板构建器并验证输出。

您可以看到,我们可以轻松地在最适合的位置添加查询的条件部分。例如,这里我们在 from 语句之后直接有一个条件 join,尽管我们仍然有多个条件检查,但它并没有使模板过于复杂。

自定义功能

另一个很好的 tqla 功能有助于提高 sql 构建器的可维护性,是能够定义我们可以在模板中使用的自定义函数来抽象一些转换逻辑。

这是我们如何使用函数将 golang 的 time.time 值转换为 sql.nulltime 的示例,以便我们可以对数据对象进行插入,而无需事先转换:

funcs := template.funcmap{
    "time": func(t time.time) sql.nulltime {
        if t.iszero() {
            return sql.nulltime{valid: false}
        }
        return sql.nulltime{time: t, valid: true}
    },
}

t, err := tqla.new(tqla.withplaceholder(tqla.question), tqla.withfuncmap(funcs))
if err != nil {
    return err
}

通过在 tqla funcs 映射中定义此函数,我们现在可以通过向其提供来自数据对象(即 time.time 字段)的参数来在查询模板中自由使用它。我们甚至可以在同一个模板中使用不同的字段多次调用这个函数。

这是一个简化的示例:

statement, args, err := t.Compile(`
    INSERT INTO events
        (name, created_at, merged_at, closed_at)
    VALUES ( 
        {{ .Name }},
        {{ time .CreatedAt }},
        {{ time .MergedAt }},
        {{ time .ClosedAt }}
    )`, eventData)

结论

总之,我们相信使用 tqla 可以帮助提高查询构建逻辑的可维护性,同时为创建动态查询提供一些强大的实用程序。模板结构的简单性允许清晰的代码可读性,并且可以更快地调试任何潜在的错误。

我们将 tqla 开源来共享这个库,希望它为其他希望以简单、可维护且安全的方式在许多不同类型的应用程序中构建 sql 查询的用户提供一个很好的选择。

如果您有兴趣,请查看存储库,如果它对您有任何帮助,请给它一个星星。请随时提出任何功能请求或错误报告!

我们始终乐于接受反馈和贡献。

为了了解未来的发展,请在 x 上关注我们或加入我们的 discord!

热门AI工具

更多
小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

539

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

616

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1296

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

811

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1906

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

5454

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

2534

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

4386

2025.06.17

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

40

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn