4
votes

Most of us might be using Spring and Hibernate for data access. I am trying to understand few of the internals of Spring Transaction Manager.

According to Spring API, it supports different Isolation Level - doc But I couldn't find clear cut information on which occasions these are really helpful to gain performance improvements.

I am aware that readOnly parameter from Spring Transaction can help us to use different TxManagers to read-only data and can leverage good performance. But it locks the table to get the data to avoid dirty-reads/non-committed reads - doc.

Assume, in few occasions, we might want to blindly insert the records into a table and retrieve the information without locking the table, a case where we never update the table data, we just insert and read [append-only]. Can we use better Isolation to gain any performance?

  1. As you see from one of the reference links, do we really require to implement/write our own CustomJPADiaelect?
  2. What's the better Isolation for my requirement?
2

2 Answers

4
votes

Read-only allows certain optimizations like disabling dirty checking and you should totally use it when you don't plan on changing an entity.

Each isolation level defines how much locking a database has to impose for ensuring the data anomaly prevention.

Most database use MVCC (Oracle, PostgreSQL, MySQL) so readers don't lock writers and writers don't lock readers. Only writers lock writers as you can see in the following example.

REPEATABLE_READ doesn't have to hold a lock to prevent a concurrent transaction from modifying your current transaction loaded rows. The MVCC engine allows other transactions to read the committed state of a row, even if your current transaction has changed it but hasn't yet committed (MVCC uses the undo logs to recover the previous version of a pending changed row).

In your use case you should use READ_COMMITTED as it scales better than other more strict isolation levels and you should use optimistic locking for preventing lost updates in long conversations.


Update

Setting @Transactional(isolation = Isolation.SERIALIZABLE) to a Spring bean has a different behaviour, depending on the current transaction type:

  • For RESOURCE_LOCAL transactions, the JpaTransactionManager can apply the specific isolation level for the current running transaction.
  • For JTA resources, the transaction-scoped isolation level doesn't propagate to the underlying database connection, as this is the default JTA transaction manager behavior. You could override this, following the example of the WebLogicJtaTransactionManager.
2
votes

Actually readOnly=truedoesn’t cause any lock contention to the database table, because simply no locking is required - the database is able to revert back to previous versions of the records ignoring all new changes.

With readOnly as true, you will have the flush mode as FlushMode.NEVER in the current Hibernate Session preventing the session from committing the transaction. In addition, setReadOnly(true) will be called on the JDBC Connection, which is also a hint to the underlying database not to commit changes.

So readOnly=true is exactly what you are looking for (e.g. SERIALIZED isolation level).

Here is a good explanation.