GORM查询updated_at条件异常:预期空结果却返回数据的解决
Hey, let's break down what's going on here and get this sorted out:
The Root Cause
The core issue here is that you're reusing the same onedays slice variable across multiple goroutines, and GORM's Find method overwrites the contents of the slice you pass to it. When you run your targeted query with the updated_at condition in the main goroutine, the goroutine running the simpler user_id-only query is writing its results to the same onedays slice afterward (or concurrently), replacing the expected empty result with those two records.
It's not a problem with GORM's query builder itself—GORM's *gorm.DB instances are safe for concurrent use because each chain (like Where().Find()) creates a new, isolated query object. The conflict is purely from sharing the result slice.
Solutions
1. Use Separate Slice Variables for Each Query
The cleanest fix is to create a dedicated slice for each query, so their results never overlap. This eliminates any cross-goroutine interference entirely:
// Main goroutine: use a local slice for your targeted query var targetedResults []Oneday if err := rDB.Where("user_id = ? AND updated_at > ?", userID, date).Find(&targetedResults).Error; err != nil { // Handle error here (log, return, etc.) } // Work with targetedResults—this won't be touched by the goroutine // Goroutine: use its own independent slice go func() { var goroutineResults []Oneday if err := rDB.Where("user_id = ?", userID).Find(&goroutineResults).Error; err != nil { // Handle goroutine-specific error } // Use goroutineResults without affecting the main query's data }()
2. Use Synchronization if You Must Share Data
If your business logic absolutely requires sharing the same slice between goroutines, you need to use a mutex to ensure only one operation writes to the slice at a time. This will serialize the queries, so they don't overwrite each other:
import "sync" // Define a mutex alongside your shared slice var ( sharedOnedays []Oneday sliceMutex sync.Mutex ) // Main goroutine query with lock sliceMutex.Lock() defer sliceMutex.Unlock() if err := rDB.Where("user_id = ? AND updated_at > ?", userID, date).Find(&sharedOnedays).Error; err != nil { // Handle error } // Goroutine query with lock go func() { sliceMutex.Lock() defer sliceMutex.Unlock() if err := rDB.Where("user_id = ?", userID).Find(&sharedOnedays).Error; err != nil { // Handle error } }()
Note: This approach will make the queries run one after another, which could impact performance. Only use this if sharing the slice is unavoidable.
3. Verify the Base Query Works
Before wrapping up, double-check that your original targeted query works in isolation to rule out any other issues:
var testResults []Oneday if err := rDB.Where("user_id = ? AND updated_at > ?", 44, "2018-01-04 23:18:00").Find(&testResults).Error; err != nil { log.Fatal(err) } fmt.Printf("Test result count: %d\n", len(testResults)) // Should output 0, matching your direct SQL result
内容的提问来源于stack exchange,提问作者rluisr

