在座位预订中回滚

时间:2015-12-28 09:27:30

标签: grails transactions

我正在制作一个座位预订模块,用户可以检查座位是否可用于考试,如果是,他可以进入付款页面,然后输入卡片​​详细信息并付款。现在我想要的是,当打开支付页面时,座位可用值应该在一段时间内减少1(直到会话到期或用户导航到其他页面)。

如果我使用数据库事务为创建操作(MVC)执行此操作,那么将无法触发控制器的操作(In grails)并保存数据库更改而不会有任何回滚的可能性。

使用db获取座位锁是否可行,或者我应该使用一些cron作业来检查它。请建议。

1 个答案:

答案 0 :(得分:0)

我假设考试永远不会被超额预订。换句话说, exactness 并发更重要。在这种情况下,悲观锁定策略是最好的选择。 注意:默认情况下,Grails使用乐观锁定。

您可以使用数据库悲观锁定来协助分配席位,但就其本身而言,数据库锁定不适合业务事务锁定。正如您所暗示的,当事务提交时会释放锁定。所以你可以做的是在数据库悲观锁定之上实现你的业务事务锁定

分配/锁定座位

我建议使用服务分配/取消分配席位,以便所有锁定代码都在一个地方完成。

import groovy.time.TimeDuration

class ExamService {
    TimeDuration allocationExpiration = new TimeDuration(0, 30, 0, 0) // 30 minutes

    SeatsAllocation allocateSeats(long examId, long userId, int numberOfSeats) {
        def exam = Exam.lock(examId)

        if(exam.seatsAvailable >= numberOfSeats) {
            exam.seatsAvailable = exam.seatsAvailable - numberOfSeats
            exam.save()

            return new SeatsAllocation(
                exam: exam,
                user: User.get(userId), 
                numberOfSeats: numberOfSeats,
                purchased: false,
                expiration: new Date() + allocationExpiration).save()            
        } else {
            return null
        }
    }     
}

在此示例中,当用户决定购买一定数量的座位但尚未实际购买时,会调用allocateSeats()。在交易的这个阶段,SeatsAllocation代表用户购买的意图。分配有一个到期日,必须在购买的确切时刻进行检查。如果分配已过期,则应禁止购买。购买代码未显示,但基本上确保将SeatsAllocation.purchased设置为true

解除分配/解锁席位

这是您提到的cron / Quartz工作的好地方。该作业将检索已过期的SeatsAllocation,使座位可用,最后删除分配。在下面的示例中,我将代码作为服务的一部分,Quartz作业可以调用它。

import groovy.time.TimeDuration

class ExamService {
    ...

    def deallocateExpiredSeats() {
        SeatsAllocation.where {
            purchased == false
            expiration < new Date()
        }.list([lock: true])
        .each { 
            it.exam.seatsAvailable = it.exam.seatsAvailable + it.numberOfSeats
            it.exam.save()
            it.delete()
        }
    }
}

请注意,使用预定作业会导致SeatsAllocation到期与可用座位之间出现延迟的问题。如果作业运行得太频繁,它将与allocateSeats()中使用的悲观锁定冲突,从而进一步降低并发性。另一方面,如果工作太频繁,那么技术上可用的座位不能分配给潜在客户,因为他们会被SeatsAllocation人质挟持。您可以根据应用的负载选择频率。