在 Golang 中处理一对多或多对多 SQL 关系时,将行映射到结构的最佳(有效、推荐、“Go-like”)方式是什么?
采用下面的示例设置,我尝试详细说明一些方法以及每种方法的优缺点,但想知道社区推荐的内容。
与 PostgreSQL 一起工作(可以是通用的但不包括 MySQL/Oracle 特定功能)
效率 - 没有暴力强制每个组合
没有 ORM - 理想情况下只使用database/sql
和jmoiron/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,
})
}
优点
一个单一的数据库调用和游标,可以在不消耗太多内存的情况下循环
缺点
在结构上使用多个连接和许多属性进行复杂且更难开发
不太高效;更多的内存使用和处理时间与更多的网络调用
慕桂英3389331
慕沐林林
江户川乱折腾
相关分类