Is there any mutual influence between JPA locks (optimistic/pessimistic) and database isolation levels (in example http://www.postgresql.org/docs/9.1/static/transaction-iso.html)?
EJB3.2 Spec (8.3.2 "Isolation levels") says that Bean Provider is responsible for setting isolation level of transaction, so generally I shouldn't care, but anyway I am still confused. In example in PostgreSQL, according to mentioned source, the default isolation level is "read commited". Does this mean, that when I do not lock any entity, the transaction isolation level will be still "read commited"?
By having #Version column on your entities and using no locking (equivalent of using LockModeType.NONE) you are implicitly working with READ_COMMITED isolation. This is achieved in the JPA layer because all updates are usually deferred until commit time or OptimisticLockException is thrown is case of an update conflict (I'm still assuming no explicit locking).
It assumes ... that writes to the database
will typically occur only when the flush method has been invoked—whether explicitly by the application,
or by the persistence provider runtime in accordance with the flush mode setting
On the database layer, JPA specification also assumes you have READ_COMMITED isolation.
It assumes that the databases to
which persistence units are mapped will be accessed by the implementation using read-committed isolation
(or a vendor equivalent in which long-term read locks are not held)
Of course manual flush/refresh, queries and flush type modes (AUTO, COMMIT) complicates the situation. Also 2nd level and query cache configuration might play a role. However with all defaults, JPA READ_COMMITED behaves pretty predictably and as a rule of thumb it is safe to accompany it with READ_COMMITED isolation at the db level.
In order to achieve REPETABLE_READ with JPA you have to use locks (but that's another story).
Lock modes are intended to provide a facility that enables the effect of “repeatable read” semantics
Related
I am aware that JPA works with the default isolation level set for the database , if no isolation level is explicitly specified using the #Transactional annotation.
So, for a simple JPA query like findByID(someId), is the transaction limited to the JPA query, or the transaction is applicable throughout the request thread ?
If I execute findById() method twice in the same thread, does it execute within the same transaction ?
If you don't specify transaction boundaries with annotations or programmatic transactions then each query executes in its own transaction.
JPA flushes before the transaction commits, so each findById will make its own database query, then flush the cached results. So if you call findById twice it will result in two queries.
You can verify this by viewing logging of transactions, see Showing a Spring Transaction in log.
Isolation level is a different issue from transaction boundaries. Most transaction properties (the A, C, and D in ACID) are all-or-nothing, but isolation isn't, it can be dialed up or down. Isolation level determines how changes in one transaction become visible to other transactions in progress.
In this page in Microsoft's documentation on EF it is stated literally
Entity Framework does not wrap queries in a transaction
If I am right, this means that sql reads are not implied with transactions and thus every select in our code is executed independently. But if this is so, can we ensure that two reads are consistent between each other? In the typical scenario, is there a warranty that the sum of the loaded amount of A and the loaded amount of B will be right (in some connection) if a transfer between A and B is started (in a different connection) between the read of A and the read of B? Would Entity Framework be able to solve this case in some way?
The built-in solution in EF is client-side optimistic concurrency. On update EF will build a query that ensures that the row to be updated has not been changed since it was read.
Properties configured as concurrency tokens are used to implement
optimistic concurrency control: whenever an update or delete operation
is performed during SaveChanges, the value of the concurrency token on
the database is compared against the original value read by EF Core.
If the values match, the operation can complete. If the values do not
match, EF Core assumes that another user has performed a conflicting
operation and aborts the current transaction.
You can also opt in to Transactions at whatever isolation level you choose, which may provide similar protections. Or use Raw SQL queries with lock hints for your target database.
Am I right with following ?
JPA: LockModeType.NONE means:
There is no explicit locking on JPA level / application layer
In the absence of explicit locking on JPA level, the application will use implicit locking
Implicit locking means, JPA is delegating the whole locking responsibility to the database system
If the database system has as default islation level, for example Committed Read, so JPA-LockModeType.NONE will cause that transactions will be handled as Committed Read
So, JPA-LockModeType.NONE is not the same as Uncommited Read because no database system has Uncommited Read as default, and it's also a little misleading because a database system always uses locks even with Uncommited Read.
is this correct ?
Env:
Java EE 7
JPA 2.1
EJB 3.1
Hibernate 4
Recently we are experiencing data problems in one of the table. Couple of points
The table is mapped to JPA entity
Table as well as Entity does not have "version" column/attribute.
In other words, there is no optimistic locking available for this table. On doing RCA, it turned out to be concurrent data modification issues.
Questions :
In such cases where #Version is not available/used (in other words optimistic locking), is using a singleton repository class is the only option to make sure data consistency is maintained ?
What about pessimistic locking in such cases ?
I believe its a general use case where an application (especially legacy) can have some tables with version column and some dont. Are there any known patterns for handling tables/entities without version column ?
Thanks in advance,
Rakesh
JPA supports pessimistic locking and you are free to use it in case you cannot or do not want to use optimistic locking.
In short, EntityManager provides lock methods to lock already retrieved entity, and also overloaded em.find and em.merge, as well as Query.setLockMode provide means to supply lock options to apply locks atomically at the time when the data is retrieved from DB.
However, with pessimistic locking, you should be aware you should prevent deadlocks. The best way to tackle it is always locking at most one entity per transaction.
You might also consider setting timeout for attempt to lock an entity, so that your transaction does not wait for long time if the entity is already locked.
In more detail, a very intelligible explanation of optimistic and pessimistic locking with JPA is provided here, including differences between READ and WRITE lock modes and setting lock timeout.
I am using Entity Framework, and I have tracked SQL Server using SQL Server Profiler. And I found that when I query the database using EF, the SQL Profiler will show the following:
set transaction isolation level read committed.
So what does this mean?
You should check the wiki about isolation levels. I guess you know transactions a little bit, the SaveContext() saves the changes in a transaction. There are several transaction levels, with increasing error filtering capabilities and decreasing performance. It is a good task to find the balance between safety and performance.
The read committed transaction level protects you from "dirty reads", but doesn't protect from "non-repeatable reads" and "phantom reads" (see wiki). Kinda deep topic, but you shall go through it once you plan to create more complicated and safe systems.
You can modify the transaction level like it is written here. But for basic applications you won't need this.