I am porting a Grails application from Oracle to MySQL database. The original Oracle version is a legacy database which uses a few complex Views leveraging Oracle's INSTEAD OF INSERT OR UPDATE feature which MySQL doesn't have. As a workaround I have implement Inser开发者_开发技巧t and Update methods on the Domain classes which point to these kinds of Views. For example,
class AdminUser {
//...
def update() {
if(this.validate()) {
Sql sql = Utils.getHibernateSql()
sql.execute(
"update table_x ...",
[...]
)
sql.execute(
"update table_y ...)",
[...]
)
sql.execute(
"update table_z ...",
[...]
)
return true
}
return false
}
//...
}
Here is a description of the problem I am running into at the moment:
- Within a service method I load an instance of AdminUser using AdminUser.get
- I modify the loaded instance and call update(), all appears well
- Once the service method finishes executing an exception is thrown due to something calling save on the instance.
How can I prevent the magical save happening in step (3) (I recently read somewhere that Grails will automatically save a modified Domain class instance which hasn't yet been saved upon exiting a service method, but I can't seem to find the link to that resource right now)?
You're leaving the modified instance in the hibernate session with dirty fields. When the hibernate session gets flushed, it will try to save the object again with the usual save()
method.
One solution would be to discard your object from the hibernate session after you've manually saved the changes. For example:
def update() {
if(this.validate()) {
Sql sql = Utils.getHibernateSql()
sql.execute(
"update table_z ...",
[...]
)
...
this.discard() // remove the object from the hibernate session
return true
}
In addition, you can add this to your Config.groovy to require that objects be saved explicitly:
hibernate.flush.mode="manual"
If you use read() instead of get(), then the object will not auto-persist changes. You can still call save() explicitly, but the standard behavior where the OpenSessionInView interceptor flushes all unsaved dirty instances will skip the instances loaded with read().
精彩评论