In a Grails app, the default behaviour of service methods is that they are transactional and the transaction is automatically rolled-back if an unchecked exception is thrown. However, in Groovy one is not forced to handle (or rethrow) checked exceptions, so there's a risk that if a service method throws a checked exception, the transaction will not be rolled back. On account of this, it seems advisable to annotate every Grails service class
@Transactional(rollbackFor = Throwable.class)
class MyService {
void writeSomething() {
}
}
Assume I have other methods in MyService, one of which only reads the DB, and the other doesn't touch the DB, are the following annotations correct?
@Transactional(readOnly = true)
void readSomething() {}
// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead?
@Transactional(propagation = Propagation.SUPPORTS)
void dontReadOrWrite() {}
In order to answer this question, I guess you'll need to know what my intention is:
- If an exception is thrown from any method and there's a transaction in progress, it will be rolled back. For example, if
writeSomething()callsdontReadOrWrite(), and an exception is thrown from the latter, the transaction started by the former will be rolled back. I'm assuming that therollbackForclass-level attribute is inherited by individual methods unless they explicitly override it. - If there's no transaction in progress, one will not be started for methods like
dontReadOrWrite - If no transaction is in progress when
readSomething()is called, a read-only transaction will be started. If a read-write transaction is in progress, it will participate in this transaction.