gpt4 book ai didi

json - 将一对多关系检索到 JSON sql pure、Golang、Performance

转载 作者:IT王子 更新时间:2023-10-29 01:02:04 27 4
gpt4 key购买 nike

假设我有以下结构,它是映射表。

type Publisher struct{
ID int `db:"id"`
Name string `db:"name"`
Books []*Book
}

type Book struct {
ID int `db:"id"`
Name string `db:"name"`
PublisherID `db:"publisher_id"`
}

所以,如果我想检索所有 Publisher 和所有相关的 Books 我想得到一个像这样的 JSON 怎么办:

[ //Publisher 1 
{
"id" : "10001",
"name":"Publisher1",
"books" : [
{ "id":321,"name": "Book1"},
{ "id":333,"name": "Book2"}
]
},
//Publisher 2
{
"id" : "10002",
"name":"Slytherin Publisher",
"books" : [
{ "id":4021,"name": "Harry Potter and the Chamber of Secrets"},
{ "id":433,"name": "Harry Potter and the Order of the Phoenix"}
]
},
]

所以我使用以下结构来检索与 Publisher

相关的所有类型的查询
type PublisherRepository struct{
Connection *sql.DB
}
// GetEbooks return all the books related with a publisher
func (r *PublisherRepository) GetBooks(idPublisher int) []*Book {
bs := make([]Book,0)
sql := "SELECT * FROM books b WHERE b.publisher_id =$1 "
row, err := r.Connection.Query(sql,idPublisher)
if err != nil {
//log
}
for rows.Next() {
b := &Book{}
rows.Scan(&b.ID, &b.Name, &b.PublisherID)
bs := append(bs,b)
}
return bs
}
func (r *PublisherRepository) GetAllPublishers() []*Publisher {
sql := "SELECT * FROM publishers"
ps := make([]Publisher,0)
rows, err := r.Connection.Query(sql)
if err != nil {
// log
}
for rows.Next() {
p := &Publisher{}
rows.Scan(&p.ID,&p.Name)
// Is this the best way?
books := r.GetBooks(p.ID)
p.Books = books
}
return ps

}

所以,这是我的问题

  1. 以最佳性能检索所有 publisher 的最佳方法是什么,因为 for 中的 for 不是最佳解决方案,如果我有 200 个出版商,平均每个出版商有 100 本书。

  2. 是 GoLang 惯用的 PublisherRepository 还是有另一种方法来创建一些东西来使用纯 sql 管理实体的事务?

最佳答案

1) 不好的是每次迭代的 sql 请求。所以这里有一个解决方案,不会对每个发布者发出额外请求:

func (r *PublisherRepository) GetAllPublishers() []*Publisher {
sql := "SELECT * FROM publishers"
ps := make(map[int]*Publisher)
rows, err := connection.Query(sql)
if err != nil {
// log
}
for rows.Next() {
p := &Publisher{}
rows.Scan(&p.ID,&p.Name)
ps[p.ID] = p
}

sql = "SELECT * FROM books"
rows, err := connection.Query(sql)
if err != nil {
//log
}
for rows.Next() {
b := &Book{}
rows.Scan(&b.ID, &b.Name, &b.PublisherID)

ps[b.PublisherID].Books = append(ps[b.PublisherID].Books, b)
}

// you might choose to keep the map as a return value, but otherwise:

// preallocate memory for the slice
publishers := make([]*Publisher, 0, len(ps))
for _, p := range ps {
publishers = append(publishers, p)
}

return publishers
}

2) 除非您只创建 PublisherRepository 一次,否则创建和关闭大量连接可能不是一个好主意。还取决于您的 sql 客户端实现,我建议(并且也已经看到许多其他 go 数据库客户端)为整个服务器建立一个连接。池是由许多 sql 客户端在内部完成的,这就是为什么你应该检查你的 sql 客户端。如果您的 sql 客户端库在内部进行池化,则为“连接”使用一个全局变量(如果在内部进行池化,则它不是真正的一个连接):

connection *sql.DB

func New () *PublisherRepository {
repo := &PublisherRepository{}
return repo.connect()
}

type PublisherRepository struct{
}

func (r *PublisherRepository) connect() *PublisherRepository {
// open new connection if connection is nil
// or not open (if there is such a state)
// you can also check "once.Do" if that suits your needs better
if connection == nil {
// ...
}
return r
}

所以每次你创建一个新的 PublisherRepository 时,它只会检查连接是否已经存在。如果你使用 once.Do,go 只会创建一次“连接”,你就完成了它。

如果您有其他结构也将使用该连接,您需要一个全局位置来存放您的连接变量,或者(甚至更好)您为您的 sql 客户端编写一个小的包装程序包,然后在您的所有结构中使用.

关于json - 将一对多关系检索到 JSON sql pure、Golang、Performance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38340859/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com