我正在开发一个系统,以启用具有增量队列编号的患者注册。我正在使用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 关注
- 121 浏览
添加回答
举报
0/150
提交
取消