我尝试使用 Grails 2.1(所以 Hibernate 和 Spring)使用以下 BidService 的“幼稚”实现来实现出价系统,但它似乎无法防止提高条件,这导致来自不同并发用户的“重复”出价。
一些信息: - BidService 默认是事务性的, - 项目和投标模型使用“版本:假”(悲观锁定)
class BidService{
BidResult processBid(BidRequest bidRequest, Item item) throws BidException {
// 1. Validation
validateBid(bidRequest, item) // -> throws BidException if bidRequest do not comply with bidding rules (price too low, invalid user, ...)
// 2. Proces Bid (we have some complex rules to process the bids too, but at the end we only place the bid
Bid bid = placeBid(bidRequest, item)
return bid
}
Bid placeBid(BidRequest bidRequest, Item item){
// 1. Place Bid
Bid bid = new Bid(bidRequest) // create a bid with the bidRequest values
bid.save(flush: true, failOnError: true)
// 2. Update Item price
item.price = bid.value
item.save(flush: true, failOnError: true)
return bid
}
}
但正如http://grails.org/doc/latest/guide/services.html 9.2 Scoped Services 中所述:默认情况下,对服务方法的访问是不同步的,因此没有什么可以阻止这些方法的并发执行。事实上,因为服务是单例的并且可能被并发使用,所以在服务中存储状态时应该非常小心。或者走简单(更好)的道路,永远不要将状态存储在服务中。
我曾想过在整个 processBid() 方法上使用“同步”,但这听起来很粗鲁,可能会引发活跃度问题或死锁。另一方面,以异步方式处理出价会阻止直接向用户发送有关赢得/输掉拍卖的反馈。
在这种情况下使用任何建议或最佳实践?
PS:我已经问过 grails ML 但这是一个相当广泛的 Java 并发问题。