nancyd-myturn commented on issue #14545: URL: https://github.com/apache/grails-core/issues/14545#issuecomment-6132413991
Still present on Grails 8.0.0 with grails-data-hibernate7 (Hibernate 7.4.10). Some detail that may help: Where. HibernateGormValidationApi.validate sets the session to FlushMode.MANUAL and restores the previous mode only when there are no errors. A failed domain validate() therefore leaves MANUAL behind, and the transaction's commit flushes nothing: changes made before the failed validate() and after it are both lost, silently. When it bites. Only when the session is in COMMIT (the default for read-write transactions, set by GrailsHibernateTransactionManager.doBegin) or already in MANUAL when validate() starts. The call runs through GrailsHibernateTemplate, whose applyFlushMode (with the default FLUSH_COMMIT) switches an AUTO session to COMMIT around the call and restores AUTO in finally, so a session in AUTO is not affected. Setting the template to FLUSH_AUTO removes that switch and restore, and the leak appears even for an AUTO session. Other observations (each covered by a test): A later passing validate() does not fix it: it restores the mode it found, which is already MANUAL. validate(['someField']) returns true while another field has errors, but the session is still left in MANUAL: the restore is decided from all errors, before the field filter. A failed validate() in an inner withTransaction that joins an outer transaction leaves the outer commit with nothing to flush. A new instance that is not in the session triggers it too. save(flush: true) after the failed validate() writes what is pending at that moment; later changes are lost. Command objects' validate(), hasErrors() and errors.rejectValue do not change the flush mode. On whether the session should flush when an object is invalid (the question earlier in this thread): the invalid instance is already protected at flush time. With save(validate: false) on an invalid instance, the pre-update listener (ClosureEventListener.onPreUpdate, run with a temporary manual flush mode that it restores) vetoes that instance's update, while the other changes of the same flush are written. So restoring the previous flush mode after a failed validate() would not let invalid data through; it would only stop unrelated, valid changes in the same transaction from being discarded. Suggested fix: restore the previous flush mode in a finally block regardless of the validation result. Workaround we use: a Spring TransactionExecutionListener added to the datastore's transaction manager that sets the session to AUTO after each read-write transaction begins and restores the previous mode at completion, with the GORM template left at FLUSH_COMMIT. The template's own restore then undoes the leak. (Investigation and wording assisted by an AI tool; the behavior above was verified with integration tests.) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
