Grails 编辑在赋值时异常更新数据库

Grails edit working abnormally updating database on value assign

我正在使用 grails-2.1.1。当我加载编辑页面时,我在控制器的编辑操作中分配了一些值。但它正在更新我的 table!虽然我没有储蓄。我该如何阻止它?

下面是我的代码。我在控制器中的编辑操作:

def edit() {
    def accTxnMstInstance = AccTxnMst.get(params.id)
    if (!accTxnMstInstance) {
        flash.message = message(code: 'default.not.found.message', args: [message(code: 'accTxnMst.label', default: 'AccTxnMst'), params.id])
        redirect(action: "list")
        return
    }

    accTxnMstInstance?.accTxnDtls?.each {
        if (it?.debitCoa != null && it?.debitCoa != "") {
            String debitCoaVal = ""
            List<String> items = Arrays.asList(it?.debitCoa?.split("\s*~\s*"))
            items.each {
                List itemList = new ArrayList()
                List<String> subItems = Arrays.asList(it.split("\^"))
                subItems.each {
                    itemList.add(it)
                }
                itemList.add("false")
                itemList.add("0")

                itemList.each {
                    debitCoaVal += it.toString() + "^"
                }
                debitCoaVal += "~"
            }

            it?.debitCoa = debitCoaVal
            debitCoaVal = ""
        }

        if (it?.creditCoa != null && it?.creditCoa != "") {
            String creditCoaVal = ""
            List<String> items = Arrays.asList(it?.creditCoa?.split("\s*~\s*"))
            items.each {
                List itemList = new ArrayList()
                List<String> subItems = Arrays.asList(it.split("\^"))
                subItems.each {
                    itemList.add(it)
                }
                itemList.add("false")
                itemList.add("0")

                itemList.each {
                    creditCoaVal += it.toString() + "^"
                }
                creditCoaVal += "~"
            }

            it?.creditCoa = creditCoaVal
            creditCoaVal = ""
        }
    }

    [accTxnMstInstance: accTxnMstInstance]
}

你可以看到我在给view赋值后并没有保存

Grails 使用 Open Session In View (OSIV) 模式,在 Web 请求开始时会打开一个 Hibernate 会话(并存储在本地线程中以使其易于访问)并在请求结束时只要没有异常请求,Hibernate 会话就会刷新并关闭。在任何刷新期间,Hibernate 查看所有 "active" 对象实例并循环遍历每个持久性 属性 以查看它是否是 "dirty"。如果是这样,即使您没有显式调用 save(),您的更改也会被推送到数据库中。这是可能的,因为当 Hibernate 从数据库行创建实例时,它会缓存原始数据以便稍后与可能更改的实例属性进行比较。

很多时候这是有帮助的行为,但在这种情况下它会成为阻碍。虽然有很多修复。一个极端的做法是禁用 OSIV,但这通常不是一个好主意,除非您知道自己在做什么。在这种情况下,您可以尝试两种应该有效的方法。

一是将AccTxnMst.get(params.id)改为AccTxnMst.read(params.id)。这不会导致实例严格 "read-only" 因为您仍然可以显式调用 save() 并且如果修改了某些内容,所有实例更改都将保留。但是对于使用 read() 检索的实例,原始数据的缓存没有完成,并且在刷新这些实例期间没有脏检查(无论如何这是不可能的,因为没有缓存数据可以比较)。

在检索不会更新的实例(无论是否进行 属性 更改)时,使用 read() 通常是一个好主意,并使代码更加自文档化。

另一种选择是在控制器操作完成之前在实例上调用 discard()。 "detaches" 来自 Hibernate 会话的实例,因此当 OSIV 过滤器在请求结束时运行并刷新 Hibernate 会话时,您的实例不会被视为脏的,因为 Hibernate 无法访问它。

read() 仅对通过 id 检索的单个实例有意义,而 discard() 对任何实例都有用,例如如果它们在映射集合中或由非 ID 查询检索(例如动态查找器、条件查询等)