更新:
经过@meltingsnower的提示,发现service的get方法没有@Transactional(readOnly = true),果然加上就好了,没加的时候get之后就有errors了,事物提交导致了所有dirty的全update了,但是因为有个errors,所以validate失败了。
这个问题太绕疼了,根本上还是该@Transactional(readOnly = true)的地方忘记加导致的。
====================================
今天遇到个Grails的非常奇怪的问题,最初的现象是entity.save失败,然后没有任何的errors
仔细检查发现save调用,没有发update sql,怀疑是dirty check没有发现变化;但是save前后对象属性对比,发现属性确实是变化了,为什么dirty check失败了呢?
介绍一下该对象名为Ticket,有一个关联对象(多对一)Warehouse
大致结构为:
class Ticket { Warehouse warehouse String deviceName String serialNumber }
在controller里面先根据id get该对象,然后连续根据参数进行数据绑定,连续几次使用binddata,然后出现问题了。
经过仔细排查,发现下面这段代码
A:
if (StringUtils.isBlank(params.warehouseId)) {
entity.warehouse = null
entity.warehouseName = null
entity.shippingAgent = null
} else {
Long wId = params.warehouseId.toLong()
Warehouse w = warehouseService.get(wId)
if (wId != entity.warehouse?.id) {
entity.warehouse = w
entity.warehouseName = w.name
entity.shippingAgent = w.shippingAgent
}
}
必须改为:
B:
if (StringUtils.isBlank(params.warehouseId)) {
entity.warehouse = null
entity.warehouseName = null
entity.shippingAgent = null
} else {
Long wId = params.warehouseId.toLong()
if (wId != entity.warehouse?.id) {
Warehouse w = warehouseService.get(wId)
entity.warehouse = w
entity.warehouseName = w.name
entity.shippingAgent = w.shippingAgent
}
}
才好用,也就是说不能调用Warehouse w = warehouseService.get(wId)
这段代码A当中如果request提交的warehouseId没有发生改变,那么就不会发update,如果改变了,就会发update;改为B,则正常发update。
所以独立写了一个函数来专门测试这个问题是否可以重现以确定是否是调用Warehouse w = warehouseService.get(wId)的问题,结果you guess what,独立函数里面,无论是否调用Warehouse w = warehouseService.get(wId),都可以正确发出update sql。
看来warehouseService.get(wId)也是受害者,只好进一步进行排除。
最后发现因为画面有个字段变化,导致第二次bindData的时候,一个boolean类型(不是Boolean)在request的时候传递了个undefined上来,即该字段绑定失败。
在binddata的include里面去掉该字段,发现全好用了;但是bindData没有报任何错误,entity.errors也一直是没有错误。
Grails的文档里面http://grails.org/doc/latest/ref/Controllers/bindData.html 明确说明:
The underlying implementation uses Spring's Data Binding framework. If the target is a domain class, type conversion errors are stored in the errors property of the domain class.
但是实际上并没有如此。
所以,现在的问题是:
如果第二次binddata错误,同时又调用了调用Warehouse w = warehouseService.get(wId),那么不发送update sql,即dirty check失败了。
如果第二次binddata错误,但是不掉用Warehouse w = warehouseService.get(wId),那么发送update sql
如果第二次binddata正确,那么无论是否调用Warehouse w = warehouseService.get(wId),都发送update sql。
but why...??? 现在正在进一步分析中,我觉得这应该是gorm的一个bug。
相关推荐
Grails Grails Grails Grails Grails
Grails 3开发邮件发送功能,完整教程!超级实用,手把手教你接入邮件发送
Grails权威指南Grails权威指南Grails权威指南Grails权威指南Grails权威指南Grails权威指南
Grails入门指南书籍和源码----下载不扣分,回帖加1分,欢迎下载,童叟无欺 getting started with grails chinese Grails入门指南书籍和源码----下载不扣分,回帖加1分,欢迎下载,童叟无欺 getting started with ...
Grails基础教程
Grails1.1中文文档
grails-2.1.zip.001
grails+Xfire webservice
Grails入门指南中文pdf -- 针对grails1.0.4更新,附加idea8 开发grails的流程
Grails项目的应用越来越多,而对于初学者来说,在Eclipse下搭建Grails项目是一个难题,这个文档将教会你如何搭建Grails项目,希望对你有所帮助。
Grails的出现并不是偶然的,而是随着Web应用的日趋复杂及Web2.0和Ajax的悄然兴起发展起来的。不过在我们继续介绍Grails之前,有必要先探究一下如今其他的Java框架及他们的用户体验,因为正是他们的积累,才会产生...
第1章 寻找grails之旅 1.1 java的困惑 1.2 webc2.0时代 1.3 java的力量 1.4 什么是grails 1.4.1 与java集成 1.4.2 简单而强大 1.4.3 吸取的经验教训 1.5 使用grails的原因 ...
在学习任何东西之前,最重要的是培养兴趣,Groovy世界最耀眼的技术之一--Grails相信大家早已耳闻,我将通过Grails实战系列文章 向您展现Grails的迷人风采,使您感受到Grails的魅力,以至疯狂地爱上Grails,并坠入...
Grails 中文 参考手册
grails3.2.8 part1
grails grails入门经典 grails入门 grails例子 grails资料 通过自学一点点积累起来的,相信对你有帮助的。
详细讲解grails开发环境配置。 详细讲解grails连接mysql数据库,crud开发
grails-2.3.6
Grails 1.3.7英文版官方参考手册,学习Grails的权威指南
grails参考文档 The Grails Framework - Reference Documentation Authors: Graeme Rocher, Marc Palmer Version: 1.0.3