Read: ID=2, Value=999
Write: ID=1, NewValue=999
程序运行时间: 10.0269079s
为什么运行时间是10秒?读和写的不是同一条数据,mysql有行锁,写的时候锁住一行, 不影响其它行读取才对
```
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"log"
"sync"
"time"
)
// Data represents a data structure in the database.
type Data struct {
ID int
Value int
}
var (
dbMu sync.Mutex
db *gorm.DB
)
func initDB() {
var err error
dsn := "root:123456@tcp(localhost:3306)/demo?parseTime=true"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
err = db.AutoMigrate(&Data{})
if err != nil {
log.Fatal(err)
}
}
func main() {
initDB()
// Initialize the database with some data
db.Create(&Data{ID: 1, Value: 100})
db.Create(&Data{ID: 2, Value: 200})
db.Create(&Data{ID: 3, Value: 300})
startTime := time.Now()
// Simulate concurrent read and write with row-level lock
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
readData(2)
}()
go func() {
defer wg.Done()
writeData(1, 999)
}()
// 等待两个 goroutine 完成
wg.Wait()
endTime := time.Now()
duration := endTime.Sub(startTime)
fmt.Printf("程序运行时间: %s\n", duration)
}
func readData(id int) {
dbMu.Lock()
defer dbMu.Unlock()
tx := db.Begin()
defer tx.Rollback()
var data Data
// 使用 FOR UPDATE 子句对特定行加排他锁
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&data, id).Error
if err != nil {
log.Fatal(err)
}
fmt.Printf("Read: ID=%d, Value=%d\n", data.ID, data.Value)
// Simulate some processing time
time.Sleep(time.Second * 5)
tx.Commit()
}
func writeData(id, newValue int) {
dbMu.Lock()
defer dbMu.Unlock()
tx := db.Begin()
defer tx.Rollback()
// 使用 FOR UPDATE 子句对特定行加排他锁
err := tx.Model(&Data{}).Where("id = ?", id).Clauses(clause.Locking{Strength: "UPDATE"}).Update("value", newValue).Error
if err != nil {
log.Fatal(err)
}
fmt.Printf("Write: ID=%d, NewValue=%d\n", id, newValue)
// 提交事务
tx.Commit()
// Simulate some processing time
time.Sleep(time.Second * 5)
}
```