我正在開發一個系統,以啟用具有增量隊列編號的患者注冊。我正在使用Go,GORM和MySQL。當多個患者同時注冊時,就會發生一個問題,他們往往會得到相同的隊列編號,這不應該發生。我試圖使用事務和鉤子來實現這一點,但我仍然得到重復的隊列編號。我沒有找到任何關于如何在事務發生時鎖定數據庫的資源。func (r repository) CreatePatient(pat *model.Patient) error { tx := r.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() err := tx.Error if err != nil { return err } // 1. get latest queue number and assign it to patient object var queueNum int64 err = tx.Model(&model.Patient{}).Where("registration_id", pat.RegistrationID).Select("queue_number").Order("created_at desc").First(&queueNum).Error if err != nil && err != gorm.ErrRecordNotFound { tx.Rollback() return err } pat.QueueNumber = queueNum + 1 // 2. write patient data into the db err = tx.Create(pat).Error if err != nil { tx.Rollback() return err } return tx.Commit().Error}
1 回答

炎炎設計
TA貢獻1808條經驗 獲得超4個贊
正如 @O. Jones 所說,事務不會在這里保存你,因為你正在提取列的最大值,在 db 之外遞增它,然后保存該新值。從數據庫的角度來看,更新的值與查詢的值無關。
您可以嘗試在單個查詢中執行更新,這將使依賴關系變得明顯:
UPDATE patient AS p
JOIN (
SELECT max(queue_number) AS queue_number FROM patient WHERE registration_id = ?
) maxp
SET p.queue_number = maxp.queue_number + 1
WHERE id = ?
在 gorm 中,您無法運行這樣的復雜更新,因此您需要使用 .Exec
我不能100%確定上述內容是否有效,因為我不太熟悉MySQL事務隔離保證。
更清潔的方式
總體而言,使用原子更新的計數器保留隊列表(按reference_id)會更干凈:
開始交易,然后
SELECT queue_number FROM queues WHERE registration_id = ? FOR UPDATE;
遞增應用代碼中的隊列編號,然后
UPDATE queues SET queue_number = ? WHERE registration_id = ?;
現在,您可以在事務提交之前在患者創建/更新中使用遞增的隊列編號。
- 1 回答
- 0 關注
- 104 瀏覽
添加回答
舉報
0/150
提交
取消