Bei der Durchführung von Datenbankabfragen stoßen wir häufig auf Paging-Abfragen. Wenn paginierte Abfragen jedoch abgebrochen werden, kann es manchmal zu zeitlichen Ungenauigkeiten kommen. Dieses Problem ist für Anwendungen von entscheidender Bedeutung, die ein präzises Timing erfordern. In diesem Artikel stellt Ihnen der PHP-Editor Baicao vor, wie Sie mit diesem Problem umgehen können, um die Genauigkeit und Präzision des Timings sicherzustellen. Wir werden einige mögliche Ursachen und Lösungen untersuchen, um Ihnen zu helfen, dieses Problem besser zu verstehen und zu lösen.
Ich habe ein Objekt, mit dem eine paginierte SQL-Abfrage erstellt wird, die es ermöglicht, die Abfrage asynchron auszuführen:
type pagedquery[t any] struct { results chan []*t errors chan error done chan error quit chan error client *sql.db } func newpagedquery[t any](client *sql.db) *pagedquery[t] { return &pagedquery[t]{ results: make(chan []*t, 1), errors: make(chan error, 1), done: make(chan error, 1), quit: make(chan error, 1), client: client, } } func (paged *pagedquery[t]) requestasync(ctx context.context, queries ...*query) { conn, err := client.conn(ctx) if err != nil { paged.errors <- err return } defer func() { conn.close() paged.done <- nil }() for i, query := range queries { select { case <-ctx.done(): return case <-paged.quit: return default: } rows, err := conn.querycontext(ctx, query.string, query.arguments...) if err != nil { paged.errors <- err return } data, err := sql.readrows[t](rows) if err != nil { paged.errors <- err return } paged.results <- data } }
Ich versuche diesen Code zu testen, insbesondere den Stornierungsteil. Mein Testcode sieht so aus:
svc, mock := createServiceMock("TEST_DATABASE", "TEST_SCHEMA") mock.ExpectQuery(regexp.QuoteMeta("TEST QUERY")). WithArgs(...). WillReturnRows(mock.NewRows([]string{"t", "v", "o", "c", "h", "l", "vw", "n"})) ctx, cancel := context.WithCancel(context.Background()) go svc.requestAsync(ctx, query1, query2, query3, query4) time.Sleep(50 * time.Millisecond) cancel() results := make([]data, 0) loop: for { select { case <-query.Done: break loop case err := <-query.Errors: Expect(err).ShouldNot(HaveOccurred()) case r := <-query.Results: results = append(results, r...) } } Expect(results).Should(BeEmpty()) Expect(mock.ExpectationsWereMet()).ShouldNot(HaveOccurred()) // fails here
Das Problem, das ich habe, ist, dass dieser Test gelegentlich in der durch meinen Kommentar angegebenen Zeile fehlschlägt, denn wenn cancel()
aufgerufen wird, gibt es keine Garantie dafür, dass, wenn ich < >switch
-Anweisung – ctx.done oder <-exit
. Die Ausführung kann an einer beliebigen Stelle in der Schleife erfolgen, bis ich die Ergebnisse an den Kanal results
sende. Aber das macht keinen Sinn, weil die Ausführung blockieren sollte, bis ich Daten vom results
-Kanal erhalte, was ich erst tun werde, wenn ich cancel()
aufrufe. Darüber hinaus verlasse ich mich beim SQL-Testen auf das Paket sqlmock, das keinerlei Fuzzing von SQL-Abfragen zulässt. Warum bekomme ich diesen Fehler und wie kann ich ihn beheben? cancel()
时,不能保证在我检查 < 的 <code>switch
语句处执行 - ctx.done 或 <-退出
。执行可以在循环中的任何位置进行,直到我将结果发送到 results
通道。但这没有意义,因为执行应该阻塞,直到我从 results
通道接收到数据,直到我调用 cancel()
后我才会这样做。此外,我依靠 sqlmock 包进行 sql 测试,它不允许对 sql 查询进行任何类型的模糊检查。为什么我会遇到此故障以及如何修复它?
我的问题是由于我自己对 go 通道缺乏了解而导致的。我认为,通过创建 chan([]*t, 1)
意味着通道在满时(即当它包含单个项目时)会阻塞,但事实并非如此。相反,当我尝试在缓冲区已满时发送到通道时,会发生阻塞。因此,通过像这样修改 results
chan([]*t, 1)
bedeutet, dass der Kanal blockiert, wenn er voll ist (d. h. wenn er ein einzelnes Element enthält), aber das ist nicht der Fall. Stattdessen kommt es zu einer Blockierung, wenn ich versuche, an den Kanal zu senden, wenn der Puffer voll ist. Ändern Sie also results
wie folgt: 🎜
func NewPagedQuery[T any](client *sql.DB) *PagedQuery[T] { return &PagedQuery[T]{ Results: make(chan []*T), // Remove buffer here Errors: make(chan error, 1), Done: make(chan error, 1), Quit: make(chan error, 1), client: client, } }
Das obige ist der detaillierte Inhalt vonTests zum Umgang mit ungenauem Timing beim Abbrechen paginierter Abfragen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!