我尝试使用Grails 2.1实现BidService的以下“天真”实现的投标系统(所以Hibernate和Spring) 但它似乎无法阻止加薪条件,这导致不同并发用户的“重复”出价。
一些信息: - BidService默认为交易, - 项目和投标模型使用“version:false”(悲观锁定)
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()方法上使用“synchronized”,但听起来相当粗鲁,可能会引发活动问题或死锁。 另一方面,以异步方式处理出价,阻止发送有关赢得/失去拍卖的直接用户反馈。
在这种情况下使用的任何建议或最佳做法?
PS:我已经问过grails ML,但这是一个相当广泛的Java并发问题。答案 0 :(得分:2)
您的服务是无状态的,因此无需同步它,在状态方面需要同步。
此外,您不需要再使用任何锁定..您不会更改现有状态,只需添加新行。此外,我不是GORM专家,但是version: false
应该关闭乐观锁定的名称,这并不意味着激活悲观锁定。
从你的问题我不明白你的问题是什么,但是独特的限制是防止数据库重复的原因。