当我们的系统负载很重,几十个并发事务时,我得到乐观锁定失败错误。应用程序在与单个数据库实例通信的多个服务器上进行负载平衡。
据我所知,其核心是GORM乐观锁定机制。新线程在原始线程中加载域变量时会更改域对象属性并尝试更改。
如果是这样,处理它的最佳方法是什么?我不想处理错误,因为滚动整个事务并不是一个好的解决方案。
我有什么选择?
声明版本为false?这是否会阻止对该域对象的乐观锁定并允许并发线程更改它,即使这意味着在没有错误的情况下相互覆盖?
通过使用Object.lock(id)检索域对象的持续时间来锁定域对象?如果没有测试,很难说性能有多大,但这是最好的方法吗?
还有其他选择吗?
下面包含相关代码。如果锁定是最好的方法,那么我如何实现它,因为Object是从未保存的父对象访问子节点的?
ProductOrderService中的第390行。
private rollbackInventory(Order order) {
order.items.each {orderItem->
Product product = orderItem.product
product.increaseQuantityBy(orderItem.qty)
product.save(flush: true)
}
}
Product domain类中的increaseQuantityBy方法如下所示:
.......
Integer qty
.......
public void increaseQuantityBy(Integer change) {
changeQuantityBy(change)
}
public void decreaseQuantityBy(Integer change) {
changeQuantityBy(-change)
}
private void changeQuantityBy(Integer change) {
qty += change
}
这是错误:
2016-04-29 08:08 -- ERROR-grails.app.controllers.com.shop.order.ProductOrderController:Exception occurred. Object of class [com.shop.Product] with identifier [5774]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.shop.Product#5774]
org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException: Object of class [com.shop.Product] with identifier [5774]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.shop.Product#5774]
at com.shop.order.ProductOrderService$_rollbackInventory_closure5.doCall(ProductOrderService.groovy:390)
at com.shop.order.ProductOrderService.rollbackInventory(ProductOrderService.groovy:387)
at com.shop.order.ProductOrderService.processOrder(ProductOrderService.groovy:178)
at com.shop.order.ProductOrderController.order(ProductOrderController.groovy:240)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:198)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:62)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.shop.Product#5774]
... 12 more