Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

...

It might make sense, then, to specify rollback for java.lang.Exception.

Read-Only / Read-Write Modes

Transactions can also be configured to be read-write (the default) or read-only.

A read-write transaction will always flush immediately before a transaction commit, whatever the OSIV interceptor flush-mode setting.

A read only transaction will not prevent updates. This is a little surprising, but updates can take place and be committed in a read-only transaction. This is because Oracle does not support read-only transactions over JDBC. Where the read-only and read-write transactions do differ is in the flush behavior. A read-write transaction will set the flush mode to automatic; this is why there is always a flush before a commit in a read-write transaction. A read-only transaction however, leaves the flush mode alone; so if the OSIV interceptor's flush mode is set to the default (i.e. never), no flush will take place at all, and changes will not be written to the database or committed. If the OSIV interceptor flush mode is set to AUTO, this flush mode will stay in effect for the read-write transaction, and a flush will occur before a commit. And of course if an explicit flush is coded within a read-only transaction, the flush will write updates to the database and, at the end of the transaction, committed.

This table summarizes the behavior:

OSIV Interceptor
Flush Mode

Read-only/
Read-write TX

Explicit flush
in transaction?

Changes committed?

Default (NEVER)

RW

N

Y

Default (NEVER)

RW

Y

Y

Default (NEVER)

RO

N

N

Default (NEVER)

RO

Y

Y

AUTO

RW

N

Y

AUTO

RW

Y

Y

AUTO

RO

N

Y

AUTO

RO

Y

Y

So the only differences in behavior between read-only and read-write transactions come when the flush mode is set to NEVER (OSIV Interceptor default) and no explicit flushes are done in the code - changes are not committed.

Put another way, the only differences in behavior between the flush modes NEVER and AUTO come in a read-only transaction with no explicit flushes in the code - changes are not committed.

Finally, a read-only transaction does not enforce a read-only policy. Given this behavior, it's not clear how useful a read-only transaction is.

Hibernate Flushing

Flushing is the process of synchronizing the state of the database with the state of persistent Java objects held in the session. What this means in practice is SQL insert, update, and delete statements being issued based on earlier Hibernate save, update, delete, and modifications to persistent objects. So the flush will write changes to the database but will not commit them.

...

In our more recent web apps, a default flush mode is set in the OpenSessionInView interceptor. The default flush mode setting for the OSIV interceptor is NEVER, although OGS and OREG use a default flush mode setting of AUTO. The recommendation in the OSIV interceptor Javadoc is for all Hibernate operations to take place in transactions, with the transaction manager to handle flushing - in this scheme, OSIV should not need to flush. We need to revisit OGS & OREG on this issue. Update: see the Read-Only / Read-Write Modes section above for a description of how these two flush modes affect transaction behavior.

JPA - currently only has two flush modes; COMMIT (required to flush only before commit - may flush at other times) and AUTO (required to flush before any query and before commit). For this reason, we should possibly not use NEVER or MANUAL, as they are Hibernate-specific and will not translate to JPA.

...

There's a lot of information here, so here's an attempt to boil it down into some practical advice:

  1. All hibernate operations should must take place within a transaction.
  2. Care should be taken to identify "units of work" and make sure a single transaction is defined around each unit.
  3. This may mean declaring a transaction around each controller method that responds to an HTTP request.
  4. We should not use the TransactionProxyFactoryBean method of configuring transactions.
  5. We should use AOP for configuring transactions in the service layer and below.
  6. We can use AOP or @Transactional for configuring transactions in the controller layer. Any given app should choose one of these methods and use it consistently.
  7. We should think about what kinds of exceptions should trigger a transaction rollback, and configure the transactions appropriately. By default, checked exceptions will NOT roll back a transaction.
  8. We can control which exceptions force a rollback.
  9. We need to be aware that dirty persistent objects WILL trigger database updates and commits unless a transaction is rolled back by the throwing of an exception.
  10. We should use the default transaction propagation setting (REQUIRED) unless there is a clear reason for using a different setting.
  11. Flush modes still need to be discussed.