假设您想在数据库中引入一个条目,比如说,由于缺乏更好的例子,您想在书籍和作者数据库中引入一个书籍条目。所以,我对于这个插入的心理模型会是这样的。
query := `
INSERT INTO books(book_id,title,publisher,year,page_count,genres)
VALUES($1,$2,$3,$4,$5,$6)
RETURNING id,book_id,title,publisher,year,page_count,genres
`
args := []interface{}{
entry.Book.Hash,
entry.Book.Title,
entry.Book.Publisher,
entry.Book.Year,
entry.Book.PageCount,
pq.Array(entry.Book.Genres)}
err := tx.QueryRowContext(ctx, query, args...).Scan(
&read.Book.ID,
&read.Book.Hash,
&read.Book.Title,
&read.Book.Publisher,
&read.Book.Year,
&read.Book.PageCount,
pq.Array(&read.Book.Genres))
if err != nil {
return err
}
query = `
WITH filter1 AS(
SELECT
UNNEST($1::TEXT[]) AS name,
UNNEST($2::TEXT[]) AS author_id,
1 as books_authored
), finished AS(
INSERT INTO authors(name,author_id,books_authored)
SELECT name, author_id, books_authored FROM filter1
ON CONFLICT (author_id) DO UPDATE
SET books_authored = authors.books_authored + 1
RETURNING id, name, author_id, books_authored
)
SELECT array_agg(id), array_agg(name), array_agg(author_id), array_agg(books_authored) FROM finished
`
args = []interface{}{pq.Array(entry.Authors.List), pq.Array(entry.Authors.Hash)}
err = tx.QueryRowContext(ctx, query, args...).Scan(
pq.Array(&read.List.ID),
pq.Array(&read.List.Name),
pq.Array(&read.List.Identifier),
pq.Array(&read.List.Books_authored),
)
if err != nil {
return err
}
query = `
WITH cte AS (
SELECT book_id, author_id FROM
UNNEST($1::TEXT[]) AS book_id,
UNNEST($2::TEXT[]) AS author_id
), finished AS (
INSERT INTO book_author_link(book_id, author_id)
SELECT book_id, author_id FROM cte
ON CONFLICT (book_id, author_id) DO NOTHING
RETURNING book_id, author_id
)
SELECT array_agg(book_id), array_agg(author_id) FROM finished
`
args = []interface{}{pq.Array([]string{entry.Book.Hash}), pq.Array(entry.Authors.Hash)}
return tx.QueryRowContext(ctx, query, args...).Scan(
pq.Array(entry.Authors.List),
pq.Array(entry.Authors.Hash),
)
一切都是使用 SQL 事务完成的,以便仅在完成前面的所有步骤后才能创建条目。所以我的问题是我是否可以同时执行第一步和第二步,检查两个 goroutine 是否成功完成并继续第三步。
有关更多信息,我确实尝试使用
sync/mutex
包但无济于事,我不知道使用 http 包锁定所有 goroutine 是否会锁定在后台运行的所有其他进程。但是当我使用sync/waitGroup
时。
我对 GoLang 也很陌生,但你可以使用通道来实现这一点。一个简约的例子: 创建两个 bool 类型的通道并为每个函数分配一个通道。每个 goroutine 将成功结果(真/假)放入其通道中。你的第三个 goroutine 可以在后台永久运行并监听两个通道。如果这两个条目都是真的,那就让你的魔法发生吧:)。第三个 goroutine 可能如下所示:
func Success(ch1, ch2 chan bool) {
for val1ok := range ch1 {
for val2ok := range ch2 {
if val1ok && val2ok {
fmt.Println("All Okay")
break
}
fmt.Println("Not Okay")
}
}
}
对于你来说,当然会有更多的逻辑。例如:结构体等等以及这本书与作者匹配吗?可能是一个想法,为两个 goroutine 提供类似于每对的主键的东西,将所有内容缓存在第三个 goroutine 中并将其分配回一起。如果比赛已处理或超过特定时间,请不要忘记删除。