我如何知道Grails模型是否在检索后发生了变化? [英] How do I know if a Grails model was changed since its retrieval?

查看:127
本文介绍了我如何知道Grails模型是否在检索后发生了变化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望多个用户能够同时在Web浏览器中编辑模型,并在保存时检测到冲突(这样,第一个写入的用户在没有第二个用户明确说明的情况下不会覆盖他们的更改) 。这里是例子:

用户A检索对象X,并在浏览器中查看它。

然后用户B检索对象X,在浏览器中查看它,修改它,并将其保存在Grails的REST api中,并将模型中的 save 保存到数据库。

然后用户A修改并保存该对象。

我希望应用程序检测到对象X已被因为用户A检索了它,我会用一些选项向用户A显示合适的消息。



如何知道模型是否已更改?请注意, isDirty 不起作用, save(flush:true)不起作用。

UPDATE



我看到一些关于乐观锁定和检测模型更改的答案, EM>提交。我想要在用户检索到检索到的变化之后进行检测。请再次阅读这个问题。



这里我将阐明为什么乐观锁定不能解决上述问题。但是,我可以想象,我可能有一种方法可以使用乐观锁定,但正如下面的答案中所述,并且如文档中所述,它无济于事。这就是为什么。



乐观锁定可以在请求中工作,而不是跨请求。如果第二个用户在第一个用户正在进行更新请求时更新对象,则乐观锁定将只允许一个用户执行更新。乐观锁定防止读取 - 修改 - 写入与相同请求中的另一个读取 - 修改 - 写入交错。以下是乐观锁定防范事件的时间线(时间从上到下):

 用户1用户2 
按提交按钮提交
更新动作
|阅读模型
|在更新操作
|中|阅读模型
| |修改模型
| |写模型
|返回
|修改模型
|写模型 - 失败
返回错误或者某事

第一个用户发布模型失败因为乐观锁定检查检测到记录自读取以来已被修改。



我想要保护的是以下时间表:

 用户1用户2 
访问网络应用访问网络应用
点击链接编辑模型点击链接编辑模型
编辑动作
|阅读模型
|渲染模型
在编辑动作
|中返回
阅读模型
|渲染模型
返回
用户编辑模型用户编辑模型
用户认为... hmm ...用户在更新动作中提交

|阅读模型
|从params
|修改模型写模型
返回
用户在更新动作
|中提交
阅读模型
|从params
|修改模型写模型 - OOPS!覆盖以前的变化
返回

从这个例子中你可以看到用户1覆盖用户2的变化。但用户1根据数据库中旧模型的旧副本进行了更改,如果她看到用户2在思考过程中发生的更改,可能会做出不同的改变。

解决方案

正如dmahapatro所说,乐观锁定是内置的。我只想补充一点,Grails脚手架在控制器的更新操作中考虑了这一点。作为一个例子,请注意它会检查版本,看它自提交以来是否已经更新过。

  def update(长ID,长版本){
def bookInstance = Book.get(id)
if(!bookInstance){
flash.message = message(code:'default.not.found.message ',args:[message(code:'book.label',default:'Book'),id])
redirect(action:list)
return
}

if(version!= null){
if(bookInstance.version> version){
bookInstance.errors.rejectValue(version,default.optimistic.locking.failure ,
[message(code:'book.label',default:'Book')] as Object [],
另一个用户在编辑时更新了这本书)
render (view:edit,model:[bookInstance:bookInstance])
return
}

$ b bookInstance.properties = params

if(!bookInstance.save(flush:true)){
render(view:edit, model:[bookInstance:bookInstance])
return
}

flash.message = message(code:'default.updated.message',args:[message(code:' book.label',default:'Book'),bookInstance.id])
redirect(action:show,id:bookInstance.id)
}


I want multiple users to be able to edit models in a web browser at the same time and conflicts detected when the save (so that the first user to write doesn't have their changes overwritten without the second user explicitly saying so). Here's the example:

User A retrieves object X and is looking at it in their browser.

Then User B retrieves object X, looks at it in their browser, modifies it, and saves it causing a post to the REST api in Grails and a save on the model to the database.

Then User A modifies and saves the object.

I want the application to detect that object X has been modified since user A retrieved it and I'll display a suitable message to user A with some options.

How do I know if the model has changed? Note that isDirty will not work and save(flush:true) will not work.

UPDATE

I see a couple answers that talk about Optimistic Locking and detecting a model change since it was submitted. I want to detect a change since it was retrieved by the user. Please read the question again.

Here I will clarify why Optimistic Locking will not solve the problem described above. However, I can imagine that there may be a way for me to use Optimistic Locking, but as it is described in the answers below and as it is described in the documentation, it will not help. Here's why.

Optimistic Locking works within the request, not across requests. If a second user updates an object while an update request is in progress from the first user, then optimistic locking will only allow one user to perform the update. Optimistic Locking protects against a read-modify-write being interleaved with another read-modify-write in the same request. Here's a time line (where time is top to bottom) of the events that optimistic locking protects against:

User 1                          User 2
presses submit                  presses submit
in update action
|   read model
|                               in update action
|                               |   read model
|                               |   modify model
|                               |   write model
|                               return
|   modify model
|   write model - FAILS
return error or something

Writing the model by the first users post fails because the optimistic locking check detects the record was modified since it was read.

What I would like to protect against is the following timeline:

User 1                          User 2
visits web app                  visits web app
clicks link to edit model       clicks link to edit model
in edit action
|   read model
|   render model
return
                                in edit action
                                |   read model
                                |   render model
                                return
user edits model                user edits model
user thinks... hmm...           user submits
                                in update action
                                |   read model
                                |   modify model from params
                                |   write model
                                return
user submits
in update action
|   read model
|   modify model from params
|   write model - OOPS! overwrote previous changes
return

From this example you can see that User 1 overwrites User 2's changes. But User 1 made her changes based on an old copy of the model from the database and perhaps would have done something different if she had seen User 2's changes that happened while she was thinking.

解决方案

Optimistic locking is built in, as dmahapatro has said. I would just add that Grails scaffolding takes this into account on the update actions for controllers. As an example, note that it checks the version to see if Book has already been updated since it was submitted.

def update(Long id, Long version) {
        def bookInstance = Book.get(id)
        if (!bookInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), id])
            redirect(action: "list")
            return
        }

        if (version != null) {
            if (bookInstance.version > version) {
                bookInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
                          [message(code: 'book.label', default: 'Book')] as Object[],
                          "Another user has updated this Book while you were editing")
                render(view: "edit", model: [bookInstance: bookInstance])
                return
            }
        }

        bookInstance.properties = params

        if (!bookInstance.save(flush: true)) {
            render(view: "edit", model: [bookInstance: bookInstance])
            return
        }

        flash.message = message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])
        redirect(action: "show", id: bookInstance.id)
    }

这篇关于我如何知道Grails模型是否在检索后发生了变化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆