Besides the obvious performance implications of doing so, what are good technical reasons not to set grails.gorm.autoFlush = true
and grails.gorm.failOnE开发者_如何学运维rror = true
in Config.groovy
?
GORM is a wrapper around Hibernate (at least that's one of the implementations - there are now also various NoSQL implementations like Redis). By setting autoFlush
to true
you're denying Hibernate the opportunity to optimise the calls it makes to the database. For example, you may cause it to insert then later update, when a single insert might have been sufficient. There's nothing inherently bad about that, it's just not necessary and is less efficient. Hibernate is clever enough to know when it needs to write to the database and can optimise - you've abstracted away that problem.
Setting failOnError
would cause save to throw an exception whenever you try to save a domain object that doesn't validate. When building an application which involves creating objects from user input it's pretty normal for objects not to validate - missing inputs, wrong formats, etc. Exception handling should be saved for exceptions and errors - it shouldn't be used for normal flow of an application. save()
returns the object when the object was successfully saved or null otherwise, which gives you a more convenient way to handle validation as part of the application flow, rather than putting try-catch blocks all over the place.
Peter Ledbrook (on of the authors of Grails in Action) has written a great series of 'GORM Gotchas' articles in which he discusses some of these issues in more detail - well worth a read: part 1, part 2 & part 3.
I use both ever and believe I have great reasons I want share with you.
Why use grails.gorm.autoFlush = true
?
Cause not really saving the entity/domain when I call save() is a not doing what I am telling the API to do. It cause many headaches when Hibernate flushs on 16 lines ahead of execution and it brings pain to debug. It your team isn't Java developer, it's a lot of pain.
Grails borrowed the Active Record Pattern from Ruby (which persistence methods are called directly, like domain.save) but that Ruby really do the persistance when save() is called, but Grails don't because they hide 'Hibernate Session' from API user/developer. It's a serious Leak Abstraction fail of GORM that we can solve with this config parameter.
Once setted, if you really need the Unit of Work Pattern of Hibernate, which chains SQL calls and do it just once for performance reasons, just use domain.save(flush:false)
when needed.
Why use grails.gorm.failOnError = true
?
Never hide an exception from user. All great Java programmer know that. If you "really really" need to hide, log it as warn. But this unfortunatelly don't happen when Grails validation fails (no log!) and make programmers blind, something really hard to novices who don't know that. The most experienced guys just say 'it's easy to tweak' but it's a mere vicious than the better way.
For the sake, these GORM Leaky Abstraction was the only complains I had with Grails in the past. Nowadays they have just gone with this config params.
Nice series of articles by Peter Ledbrook about GORM :
- http://spring.io/blog/2010/06/23/gorm-gotchas-part-1/
- http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/
- http://spring.io/blog/2010/07/28/gorm-gotchas-part-3/
Although I disagree with him about what the Hibernate session flush does. He says that "The flush: true forces Hibernate to persist all changes to the database right away". Well, that would only happen in a non transactional context , because when you are within a transaction, the #SQL statements that are flushed from the Hibernate session, will be executed in the rollback segment of your transactional RDBMS. So they won't be trully persisted until the transaction has been committed.
When within a transaction you are performing other non-DB related operations, like sending a confirmation email, you want to know if any constraint or DB runtime error that is not explicitly declared in your validation has occurred before, for instance, you sent that confirmation email.
My advice is that the autoFlush (grails.gorm.autoFlush = true) strategy is not wrong per se. You have to make the technical decision abouth whether you want to use it or not at the beginning, so developers can write their code accordingly as they will know if the flush has to be performed explicitly or Hibernate will do it for them at the end of you transaction method.
Another common use case to consider is if you want to perform a batch operation using GORM. If you don't flush your Hibernate session every whatever number of SQL operations, you will run into problems.
精彩评论