当前位置:首页 > 文章列表 > Golang > Go问答 > 高效地将一对多多对多数据库映射到 Golang 中的结构

高效地将一对多多对多数据库映射到 Golang 中的结构

来源:Golang技术栈 2023-03-23 09:25:47 0浏览 收藏

小伙伴们对Golang编程感兴趣吗?是否正在学习相关知识点?如果是,那么本文《高效地将一对多多对多数据库映射到 Golang 中的结构》,就很适合你,本篇文章讲解的知识点主要包括golang。在之后的文章中也会多多分享相关知识点,希望对大家的知识积累有所帮助!

问题内容

在 Golang 中处理一对多或多对多 SQL 关系时,将行映射到结构的最佳(高效、推荐、“Go-like”)方法是什么?

以下面的示例设置为例,我尝试详细说明每种方法的优缺点,但想知道社区推荐什么。

要求

  • 适用于 PostgreSQL(可以是通用的,但不包括 MySQL/Oracle 特定功能)
  • 效率 - 没有暴力破解每个组合
  • 没有 ORM - 理想情况下只使用database/sqljmoiron/sqlx

例子

为了清楚起见,我删除了错误处理

楷模

type Tag struct {
  ID int
  Name string
}

type Item struct {
  ID int
  Tags []Tag
}

数据库

CREATE TABLE item (
  id                      INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
);

CREATE TABLE tag (
  id                      INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  name                    VARCHAR(160),
  item_id                 INT REFERENCES item(id)
);

方法 1 - 选择所有项目,然后为每个项目选择标签

var items []Item
sqlxdb.Select(&items, "SELECT * FROM item")

for i, item := range items {
  var tags []Tag
  sqlxdb.Select(&tags, "SELECT * FROM tag WHERE item_id = $1", item.ID)
  items[i].Tags = tags
}

优点

  • 简单的
  • 容易明白

缺点

  • 随着数据库查询的数量与项目数量成比例地增加,效率低下

方法 2 - 手动构建 SQL 连接和循环遍历行

var itemTags = make(map[int][]Tag)

var items = []Item{}
rows, _ := sqlxdb.Queryx("SELECT i.id, t.id, t.name FROM item AS i JOIN tag AS t ON t.item_id = i.id")
for rows.Next() {
  var (
    itemID  int
    tagID   int
    tagName string
  )
  rows.Scan(&itemID, &tagID, &tagName)
  if tags, ok := itemTags[itemID]; ok {
    itemTags[itemID] = append(tags, Tag{ID: tagID, Name: tagName,})
  } else {
    itemTags[itemID] = []Tag{Tag{ID: tagID, Name: tagName,}}
  }
}
for itemID, tags := range itemTags {
  items = append(Item{
    ID: itemID,
    Tags: tags,
  })
}

优点

  • 单个数据库调用和游标,可以在不消耗太多内存的情况下循环

缺点

  • 结构上的多个连接和许多属性使开发变得复杂且困难
  • 不太高效;更多的内存使用和处理时间与更多的网络调用

失败的方法 3 - sqlx 结构扫描

尽管失败了,但我想包含这种方法,因为我发现它是我目前的目标,即效率与开发简单性相结合。我希望通过db在每个结构字段上显式设置标签sqlx可以进行一些高级结构扫描

var items []Item
sqlxdb.Select(&items, "SELECT i.id AS item_id, t.id AS tag_id, t.name AS tag_name FROM item AS i JOIN tag AS t ON t.item_id = i.id")

不幸missing destination name tag_id in *[]Item的是,这个错误导致我相信StructScan它不够先进,无法递归循环遍历行(没有批评 - 这是一个复杂的场景)

可能的方法 4 - PostgreSQL 数组聚合器和GROUP BY

虽然我确信这 行不通 ,但我已经包含了这个未经测试的选项,看看它是否可以改进,以便它 可以 工作。

var items = []Item{}
sqlxdb.Select(&items, "SELECT i.id as item_id, array_agg(t.*) as tags FROM item AS i JOIN tag AS t ON t.item_id = i.id GROUP BY i.id")

当我有时间时,我会尝试在这里进行一些实验。

正确答案

postgres中的sql:

create schema temp;
set search_path = temp;
create table item
(
  id INT generated by default as identity primary key
);

create table tag
(
  id      INT generated by default as identity primary key,
  name    VARCHAR(160),
  item_id INT references item (id)
);

create view item_tags as
select id,
  (
          select
            array_to_json(array_agg(row_to_json(taglist.*))) as array_to_json
          from (
                select tag.name, tag.id
                 from tag
                         where item_id = item.id
               ) taglist ) as tags
from item ;


-- golang query this maybe 
select  row_to_json(row)
from (
    select * from item_tags
) row;

然后golang查询这个sql:

select  row_to_json(row)
from (
    select * from item_tags
) row;

并解组去结构:

亲:

  1. postgres 管理数据的关系。使用 sql 函数添加/更新数据。

  2. golang 管理业务模型和逻辑。

这是简单的方法。

.

今天带大家了解了golang的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

版本声明
本文转载于:Golang技术栈 如有侵犯,请联系study_golang@163.com删除
为什么 golang 中的 rune 是 int32 而不是 uint32 的别名?为什么 golang 中的 rune 是 int32 而不是 uint32 的别名?
上一篇
为什么 golang 中的 rune 是 int32 而不是 uint32 的别名?
Golang 将 image.Image 转换为 []byte
下一篇
Golang 将 image.Image 转换为 []byte
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    3182次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    3393次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    3425次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    4530次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    3802次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码