Hey everyone, I was reading about this behavior an...
# questions
u
Hey everyone, I was reading about this behavior and came across something unexpected regarding Services. It seems that using certain verbs in the method name can cause the transaction to be lost, which means the operation may never be persisted to the database (issue: https://github.com/apache/grails-core/issues/14539). This appears to be more common in Grails 3+, but still something to avoid in Grails 2 as well. Does anyone know the underlying reason for this behavior, and whether there’s a recommended workaround or best practice to avoid it? Thanks!
j
it's not that the transaction is "lost" it's that the setter doesn't get wrapped in the transaction
when you annotate a method with
@Transactional
code is injected so that looks something like this: // start transaction try { // call original code } catch(e) { // handle error / rollback }
first, generally is a bad idea to have a stateful service - since services are singletons by default
but apparently, for whatever reason, grails has supported it historically
It's probably b/c the Transactional annotation can be used anywhere as an AST transform, and it was proprobably to keep it simple that they made it not apply to bean methods - get/setters
If someone wanted to add an attribute to the Transactional annotation and change the AST transform to apply to bean methods, it's probably a reasonable change since you'd have to opt-in to that behavior and on services you're likely going to want that
so i guess what i'm saying is Pull Requests are welcome 😃
u
All right Take a look at this snippet: https://github.com/apache/grails-core/blob/7.0.x/grails-datamapping-core/src/main/[…]re/gorm/transform/AbstractMethodDecoratingTransformation.groovy Grails literally checks whether a method name starts with getXXX or setXXX. Doesn’t this look like a bit of a gotcha? Does anyone know the reasoning behind this design choice?
j
remember that hibernate hydrates objects via getter/setters - you don't want to be invoking a transaction when calling those.
it makes sense to exclude them on stateful beans, and stateless (typically services) makes sense to probably include them. I think ti's just a case of optimizing for the stateful case. I'm not opposed to fixing it by making it an opt-in
another example: one of the side effects of wrapping a method is that if an exception is caught in that catch block above, it will roll back the current transaction - but for getter/setters an exception may be expected behavior.
g
this burnt me as well.. my rough suggestion would be for the compiler or something to throw a louder warning/error when a set/get name collision occurs outside of the convention of it being in a Domain object
👍 1
j
If you added such a warning it would be a LOT of noise - the state of the bean isn't known until runtime and
@Transactional
can be used anywhere in the application
g
It'd only make noise if someone had put a function in a class with a set or get prefix, yes? Seems rare enough
j
that actually happens a lot in my project
g
Ah, and all those functions aren't participating in transactions i take it?
j
most of them are stateful beans, so yes they are not
prototype beans that have local state on them for the duration of teh run (mostly processes/background jobs)