Spring @Transactional read-only propagation
spring, transactions
Solution
First of all, since Spring doesn't do persistence itself, it cannot specify what `readOnly` should exactly mean. This attribute is only a hint to the provider, the behavior depends on, in this case, Hibernate.
If you specify `readOnly` as `true`, the flush mode will be set as `FlushMode.NEVER` in the current Hibernate Session preventing the session from committing the transaction.
Furthermore, setReadOnly(true) will be called on the JDBC Connection, which is also a hint to the underlying database. If your database supports it (most likely it does), this has basically the same effect as `FlushMode.NEVER`, but it's stronger since you cannot even flush manually.
Now let's see how transaction propagation works.
If you don't explicitly set `readOnly` to `true`, you will have read/write transactions. Depending on the transaction attributes (like `REQUIRES_NEW`), sometimes your transaction is suspended at some point, a new one is started and eventually committed, and after that the first transaction is resumed.
OK, we're almost there. Let's see what brings `readOnly` into this scenario.
If a method in a read/write transaction calls a method that requires a readOnly transaction, the first one should be suspended, because otherwise a flush/commit would happen at the end of the second method.
Conversely, if you call a method from within a readOnly transaction that requires read/write, again, the first one will be suspended, since it cannot be flushed/committed, and the second method needs that.
In the readOnly-to-readOnly, and the read/write-to-read/write cases the outer transaction doesn't need to be suspended (unless you specify propagation otherwise, obviously).
Problem
I'm experimenting with using the command pattern to allow my web layer to work with Hibernate entities within the context of a single transaction (thus avoiding lazy loading exceptions). I am, however, confused now with how I should deal with transactions. My commands call service layer methods that are annotated with `@Transactional` annotations. Some of these service layer methods are read-only - e.g. `@Transactional(readOnly = true)` - and some are read/write. My service layer exposes a command handler that executes commands passed to it on behalf of the web layer. ``` @Transactional public Command handle(Command cmd) throws CommandException ``` I assume I am right in making the command handler's `handle` method transactional. This is where the confusion comes in. If the implementation of a command makes calls to multiple service layer methods, there is no way for the command handler to know whether operations called within the command will be read-only, read/write or a combination of the two. I don't understand how propagation works in this example. If I were to make the `handle()` method `readOnly = true`, then what happens if the command then calls a service layer method that is annotated with `@Transactional(realOnly = false)`?