更新:
经过@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 3开发邮件发送功能需要对邮件发送协议和...
3. **GORM(Grails Object-Relational Mapping)**:Grails的内置ORM工具,允许开发者以声明式的方式操作数据库,支持SQL的CRUD操作,简化了数据持久化的过程。GORM支持多种数据库,如MySQL、PostgreSQL等。 4. **...
**Grails 框架详解** Grails 是一个基于 Groovy 语言的开源Web应用程序框架,它构建在Java平台之上,旨在简化开发过程并提高生产力。Grails 的设计深受Ruby on Rails的影响,提供了MVC(模型-视图-控制器)架构模式...
【Grails项目搭建详解】 Grails是一个基于Groovy语言的开源Web应用框架,它简化了开发过程,尤其适合快速构建动态网站。在Eclipse中搭建Grails项目可能相对复杂,但通过以下步骤,即使是初学者也能顺利进行。 1. *...
Grails 的强大之处在于其丰富的插件库,如Spring Security用于安全控制,Hibernate Search提供全文搜索功能,以及各种用于支付、邮件发送、社交网络集成的插件,极大地扩展了框架的功能。 6. **IDE集成** ...
如果你遇到因插件导致的编辑错误,可以在 `grails-app/conf/BuildConfig.groovy` 文件中添加以下配置: ``` grails.project.plugins.dir="./plugins" ``` 这将恢复旧的插件存储位置,从而解决编辑问题。 3. **...
- CRUD操作:Grails自动生成了保存和创建新记录的方法,如`save()`,开发者无需编写复杂的SQL语句。 3. **读取数据(Read)** - 查询:GORM提供了丰富的查询API,如`findAll()`, `findOne()`, `findById()`, `...
《Grails用户手册》 Grails,作为一个基于Groovy语言的开源Web应用框架,深受开发者喜爱,它简化了Java开发的复杂性,提供了强大的MVC(Model-View-Controller)架构,以及丰富的插件系统。这份用户手册将帮助你...
通过GORM(Grails Object Relational Mapping),Grails提供了自动的ORM支持,使得开发者无需编写复杂的SQL语句即可实现数据的持久化操作。 #### Controllers(控制器) 控制器(Controllers)负责处理来自用户的...
本项目是一个关于Grails的演示示例,特别关注了数据模型的一对多和多对多关系的配置,以及对MySQL和SQL Server数据库的支持。 1. **一对多关系配置** 在Grails中,一对多关系是通过在模型类中定义`hasMany`属性来...
对于Grails开发,我们需要的是Eclipse中的Grails插件,它能够提供对Grails项目的创建、运行、调试等一系列功能。 **Grails**是基于Groovy语言的全栈式Web开发框架,它借鉴了Ruby on Rails的设计理念,提供了快速...
3. **领域驱动设计(Domain-Driven Design, DDD)**:Grails的域类直接映射到数据库表,文档会解释如何定义领域类、关联关系,以及Lifecycle方法,如`beforeInsert`、`beforeUpdate`等。 4. **服务层**:Grails的...
**Grails 概述** Grails 是一个基于 Groovy 语言的开源 web 应用程序框架,它构建在 Java 平台上,旨在提高开发效率,简化常见 Web 开发任务。Grails 遵循 Model-View-Controller (MVC) 架构模式,允许开发者快速...
Grails 的动态方法如`save()`, `delete()`, `update()`等,使得数据操作更加直观,减少了大量手写SQL的需求。 10. **国际化与本地化** Grails 支持多语言环境,通过i18n资源文件,轻松实现应用的国际化和本地化。...
在Grails中,Ajax不仅可以与控制器进行通信,获取或发送数据,还可以与服务层、领域模型等进行交互,实现复杂业务逻辑。Grails的响应式Controller特性使得返回Ajax响应变得更加简单,可以直接返回JSON或XML格式的...
验证是Web开发中不可或缺的一部分,Grails通过声明约束和验证约束来实现。它支持客户端验证,使得可以在用户提交表单之前校验数据。Grails的国际化支持非常好,开发者可以通过简单的配置来为不同的语言环境定制应用...
在这个例子中,你可能学会了如何在Grails中使用`groovy.sql.Sql`类或者HQL(Hibernate Query Language)进行定制化查询。 3. **分页功能**:在Web应用中,数据分页是很常见的需求。Grails提供了方便的分页API,可以...
### Grails 快速开发 Web 应用程序 #### 一、Grails 概述 Grails 是一种基于 Groovy 的开源应用框架,用于简化 Web 应用程序的开发过程。它采用约定优于配置的原则,这使得开发者可以更快地创建功能丰富的 Web ...