回答

收藏

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

技术问答 技术问答 626 人阅读 | 0 人回复 | 2023-09-14

问题在Golang一对多或多对多的中处理SQL在关系中,将线映射到最佳结构(高效,推荐类似Go什么是方式?
( q0 p/ Z7 k5 R以下示例为例。我试图详细介绍每种方法的优缺点,但我想知道社区的建议是什么。8 b: C% R7 n' f, {3 A; ]
要求适用于PostgreSQL(可以通用,但不包括MySQL / Oracle特定功能)
& ^3 M0 U  z4 E) c3 U6 @. z0 ~( @效率-每种组合都不会被强迫3 s% x6 e' E" U/ s2 r, F
没有ORM-仅在理想情况下使用database/sql和jmoiron/sqlx
例子为了明确起见,我删除了错误的处理( l& f3 }4 j" _5 X) u
楷模
* s+ v) l- k' t1 b: @  s7 }type Tag struct {  ID int  Name string}type Item struct {  ID int  Tags []Tag}数据库
, l& x  Z6 ^2 \$ \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-选择所有项目,然后为每个项目选择标签
# T! j4 o$ Q* h; F+ Z; A) @var items []Itemsqlxdb.Select(&items,&quot;SELECT * FROM item&quot;)for i,item := range items {  var tags []Tag  sqlxdb.Select(&tags,&quot;SELECT * FROM tag WHERE item_id = $1&quot;,item.ID)  items<i>.Tags = tags}优点
( ^9 `: k) B+ ^9 z( p简单的5 o( P# ~/ l7 s# v2 X. ~* Z1 N
容易明白
缺点
) M: w# d$ a6 C( N/ z数据库查询数量与项目数量成正比方法2-构造SQL连接并手动遍历行" D! P- X  }/ f" i5 a1 U0 J6 d5 ]9 H
var itemTags = make(map[int][]Tag)var items = []Item{}rows,_ := sqlxdb.Queryx(&quot;SELECT i.id,t.id,t.name FROM item AS i JOIN tag AS t ON t.item_id = i.id&quot;)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, })}优点  g( b% r& a+ ]3 r7 v( B
单个数据库调用和游标可以在不占用太多内存的情况下循环缺点! G& `( X) n5 K! h8 I" Z# V
复杂且难以开发多个连接和结构的许多属性' S6 u) q0 p! w. g
性能不好;更多的内存使用和处理时间,而不是更多的网络调用
失败的方法3-SQLX结构扫描
7 \  C5 U6 p4 g* n( e% Z虽然失败了,但我还是想包括这个方法,因为我发现它是我目前效率和发展简单性相结合的目标。我的希望是通过db标签设置在每个结构字段上sqlx可以扫描一些高级结构7 o7 i3 A6 s- F
var items []Itemsqlxdb.Select(&items,&quot;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&quot;)不幸的是,这个错误使得missing destination name tag_id in*[]Item我相信消息StructScan还不够先进,不能递归历行(无可奉告-这是一个复杂的场景)  c- ^7 }% {' z) ^
可能的方法4-PostgreSQL数组聚合器和GROUP BY
; P& ?+ S9 g1 U1 H5 T5 W尽管我相信这将 不会    工作,我已经包含了这个未经测试的选项,看看它是否可以改进 可    工作。; N6 X7 P5 Z6 U
var items = []Item{}sqlxdb.Select(&items,&quot;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&quot;)有时间的时候,我会试着在这里做一些实验。5 \+ U5 c2 F; i: }. V
                                                               
: o  m6 ?' \( v8 }4 a. k    解决方案:                                                               
7 {2 t/ v+ _6 P  X1 g9 t7 D  j3 n/ }+ x                                                                postgres中的sql:0 H! G3 x1 \" g5 Q- n  T4 D! H$ }
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 asselect 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 tagsfrom item ;-- golang query this maybe select  row_to_json(row)from (    select * from item_tags) row;然后golang查询这个SQL:
+ D9 j  c) |& H( r9 }1 Q+ Oselect  row_to_json(row)from  select * from item_tags) row;并解组结构:
4 b# o( q! d: X  o5 E# e优点:5 y' Z5 S. \6 J
[ol]postgres管理数据关系sql函数添加/更新数据。
4 v2 }1 D# L( T1 c. |1 q9 X  dgolang管理业务模型和逻辑。
5 t) f1 M. E4 e2 T% c[/ol]这是一个简单的方法。6 q  @1 M! ~" g; _. ^# K' N% `
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则