Grails悲观锁和乐观锁

乐观锁(Optimistic Locking)

 

默认情况下,所有GORM类都被配置上了乐观锁,hibernate的乐观锁是通过在数据中加入一个version字段,每次数据更新时同时增长version的值来实现的。

在Grails中,持久化类读入数据时,会将数据库中的version字段的值保存在类的version属性用来表示当前实例的版本,可以像这样访问版本号:

当执行更新时,hibernate会自动对比当前实例和数据库中version的版本,如果版本不一致将会抛出StaleObjectException并回滚事务。

这种机制在不使用悲观锁时一定程度上保证了原子性,缺点是必须自己处理抛出的异常,在高并发的情况下不断的抛出异常会让用户体验变得非常差。

处理异常的方法依赖于具体的应用,一般来可以返回一个精简的错误提示给用户,让用户自己决定怎么解决冲突。

当用户体验变得非常差时,可以考虑用悲观锁。

注意:只有当hibernate会话刷新后,version才会被更新

 

 

悲观锁(Pessimistic Locking)

 

悲观锁相当于锁定了数据库中一行记录执行一个SQL "SELECT * FOR UPDATE"语句。这暗示了其他的读操作将被阻塞直到锁被释放。

在Grails中悲观锁通过调用实例的lock方法来实现:

当事务提交后,Grails会自动释放锁。在上面的代码中,相当于做了SELECT to a SELECT..FOR UPDATE两次操作,在get()和lock()方法之间,其他线程依然有可能会更新这条记录。

解决这个问题的办法可以通过调用实例静态的lock()方法,像get()方法一样传入一个id:

在这种情况下,只有SELECT..FOR UPDATE操作,从而避免了记录被修改的问题。

此外也可以通过查询来获得悲观锁,例如使用Grails dynamic finder:

或者使用criteria:

 

 

发表评论