What's the difference between DbUpdateConcurrencyException and 40001 postgres code? - postgresql

I have two transactions.
In first I select an entity, do validations, upload provided by client file to S3 and then update this entity with info about S3 file.
Second transaction is simply deleting this entity.
Now, assume that someone called first transaction and immediately second. Second one will proceed faster and first one will throw DbUpdateConcurrencyException, as selected entity no longer exists on update query.
I get DbUpdateConcurrencyException, when my transaction has IsolationLevel.ReadCommited. But if I set IsolationLevel.Serializable it throws InvalidOperationException with 40001 postgres code. Could someone explain why do I get different errors, because it seems to me that outcome should be the same, as both errors invoked by updating non-existing entity?

The 40001 error corresponds to the SQLSTATE serialization_failure (see the table of error codes).
It's generated by the database engine in serializable isolation level when it detects that there are concurrent transactions and this transaction may have produced a result that could not have been obtained if the concurrent transactions had been run serially.
When using IsolationLevel.ReadCommited, it's impossible to obtain this error, because choosing this level of isolation precisely means that the client-side doesn't want to have these isolation checks being done by the database.
On the other hand, the DbUpdateConcurrencyException is probably not generated by the database engine. It's generated by the entity framework. The database itself is fine with an UPDATE updating zero row, it's not an error at the SQL level.
I think you get the serialization failure if the database errors out first, and the DbUpdateConcurrencyException error if the database doesn't error out, but the second layer in the order of layering (the EF) does.
The typical way to deal with serialization failures, at the serializable isolation level, is for the client-side to retry the transaction when it gets a 40001 error. The retried transaction will have a fresh view of the data and hopefully will pass (otherwise, loop on retrying).
The typical way to deal with concurrency at lesser isolation levels like Read Committed it to explicitly lock objets before accessing them to force the serialization of concurrent transactions.

Related

Issue with timing of SQL query firing in JPA

I am using JPA for data persistence.
I am unable to explain a behaviour in my program.
I have an entity A which has another entity B as its member.In my code I create new instance of A and set an instance of B (fetched from database) in A,and then I save A using EntityManager. I am using container managed transaction, hence all transactions are supposed to commit at end of the method.
In very same method, after persisting A, I try to fetch an entity of class C. C, like A, has B as its member. I use a JQPL query to fetch C for id of B's instance I associated with A's instance previously.
Issue is that while fetching C, JPA is also executing SQL query to save A. I expect that to happen at end of transaction (ie when method ends).
But its happening while I try to fetch C. If I don't fetch C, then SQL query for saving A is issued when method ends.
What can be the reason for this behaviour?
JPA provider needs to flush the persistence context before query execution if there is the possibility that query results would not be consistent with the current persistent context state.
You can set flush mode to COMMIT for the desired (or all) sessions. Just keep in mind to manually flush the session if a query depends on the dirty persistence context state. Default flush mode is AUTO, meaning that persistence context may be flushed before query execution.
The reason is the database isolation level. It's read_commited by default.
Read more about isolation levels here:
https://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Read_committed
So to not break this isolation JPA MUST execute all SQL statements in the buffer that all data in the transaction has reached the database.

How to set isolation level in #Transactional "READ_UNCOMMITTED". I am using EclipseLink 2.5.1-RC1

I have a requirement to start new Transaction within an ongoing Transaction so that an exception in 2nd transaction will rollback only new transaction not the old one.
This I am doing by setting propagation attribute in 2nd transaction like this:
#Transactional(propagation = Propagation.REQUIRES_NEW)
This created a new Transaction, but the new Transaction needs to read some uncommitted data of the first transaction (dirty read), and also update that data. This I am trying to do by setting isolation attribute as :
#Transactional(propagation = Propagation.REQUIRES_NEW, isolation=Isolation.READ_UNCOMMITTED)
This throws an Exception - InvalidIsolationLevelException, saying "Standard JPA does not support custom isolation levels - use a special JpaDialect for your JPA implementation".
Can any help me to implement JpaDialect? I am using Eclipse Link 2.5.1 .
Or can I some how close the first transaction before starting a new transaction? Since First transaction is closed, the Second will have no problem reading the data committed by First Transaction.
In JPA you can try somehting like this, not much certain on how to achieve similar in EclipseLink/Spring.
But the overall concept might remain same, get the underlying database connection & set appropriate isolation level.
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
//-- Or with some other constant something like Isolation.READ_UNCOMMITTED
Afterwards, you might also want to reset the isolation level back to the default.
If you don't want to make changes, then you might need to implement JpaDialect overriding methods to accommodate the change for isolation level in transaction.
You can refer here which describes implementation for Hibernate, can try similar for EclipseLink.

PESSIMISTIC_READ lock on same entity cannot be acquired by 2 services

From JPA documentation, PESSIMISTIC_READ lock on an entity can be acquired if no one is holding a PESSIMISTIC_WRITE lock on the entity. However, as I tested using OpenJPA 2.0.0, WebSphere and MSSQL (as well as DB2), it seems that 2 services cannot acquire PESSIMISTIC_READ lock on the same entity at the same time.
This code (in ConfigEJB) was used to lock the entity:
ConfigEntity configEntity = this.getEntityById(1); // successfully get the entity
this.entityManager.lock(configEntity, LockModeType.PESSIMISTIC_READ);
2 instances of ConfigEJB were invoked. The first instance could acquire the lock successfully. However, the second instance couldn't get the lock, and was blocked until the first instance finished its transaction (I expected it to successfully get the lock).
Has anyone ever encountered this problem? Or is this an expected behavior of JPA? How to let the services obtain PESSIMISTIC_READ locks properly?
Not found in reference, but Pro JPA2 saying:
Some databases support locking mechanisms to get repeatable read isolation without acquiring a write lock. A PESSIMISTIC_READ mode can be used to pessimistically achieve repeatable read semantics when no writes to the entity are expected. The fact that this kind of situation will not be encountered very often, combined with the allowance that providers have of implementing it using a pessimistic write lock, leads us to say that this mode is not one to be easily picked up and commonly used.
So, seems your database provider replace PESSIMISTIC_READ with PESSIMISTIC_WRITE

entity framework concurrency: transactions or concurrency fixed?

I need to make stock control, so I need to ensure that when I modified the amount of product, is doing in the right way. I am using Entity framework 4.0
For example, if I use a transaction, when I load the record from the database, the recored is blocked, so I can substract or add to the loaded amount, the number of items that I need. However, this block the record in the database and perhaps for performance reasons is not the best way. This makes me ask when to use transactions with EF.
The other option is to use the concurrency fixed of entity framework, using a timespan column to detect if the record has been changed. In this case, if the record has been modified between my load and my update, I get the exception of concurrency. But it could occur that in my exception handler, if I update my context with the database data, between my refresh and the savechanges could be changed again.
Other problem is I finally can save the changes. For example, I have 10 units, I need to substract 8 but between my load and my update, other person substract 5 units. If I subtract 8, then in stock I have -3 units. This is not possible. If I have a transaction, I load the record, is blocked, so I can check if I have enough units, if yes, I can subtrack, if not, I send an exception.
So my question is, I know that EF is a transaction by itself, but it exists also transactions in EF, so it would be useful in some cases. When to use EF and cocurrency fixed and when to use transactions?
Thanks.
Daimroc.
Transactions should not be used to solve concurrency. You should make transactions as short as possible to not block your databases. The way to go here is optimistic concurrency - in the database (SqlServer) you create a rowversion column that changes automatically each time a row is modified. You use it as concurrency token. When saving changes EF checks this against the value on the entity and if they don't match it throws an exception.
Note that for SaveChanges EF always creates a transaction since typically you save more than one entity and if something goes wrong the database needs to be reverted to the original state - otherwise it would be in a corrupt state.
To prevent from going below zero - if you use the optimistic concurrency - you won't be able to save if the value in the database changed since the concurrency token will be different because row was modified and therefore the check on the client should be sufficient. Alternatively you could map saving an entity to a stored procedure that will check the value before saving and would return an error if the value after saving would be incorrect.

Create new or update existing entity at one go with JPA

A have a JPA entity that has timestamp field and is distinguished by a complex identifier field. What I need is to update timestamp in an entity that has already been stored, otherwise create and store new entity with the current timestamp.
As it turns out the task is not as simple as it seems from the first sight. The problem is that in concurrent environment I get nasty "Unique index or primary key violation" exception. Here's my code:
// Load existing entity, if any.
Entity e = entityManager.find(Entity.class, id);
if (e == null) {
// Could not find entity with the specified id in the database, so create new one.
e = entityManager.merge(new Entity(id));
}
// Set current time...
e.setTimestamp(new Date());
// ...and finally save entity.
entityManager.flush();
Please note that in this example entity identifier is not generated on insert, it is known in advance.
When two or more of threads run this block of code in parallel, they may simultaneously get null from entityManager.find(Entity.class, id) method call, so they will attempt to save two or more entities at the same time, with the same identifier resulting in error.
I think that there are few solutions to the problem.
Sure I could synchronize this code block with a global lock to prevent concurrent access to the database, but would it be the most efficient way?
Some databases support very handy MERGE statement that updates existing or creates new row if none exists. But I doubt that OpenJPA (JPA implementation of my choice) supports it.
Event if JPA does not support SQL MERGE, I can always fall back to plain old JDBC and do whatever I want with the database. But I don't want to leave comfortable API and mess with hairy JDBC+SQL combination.
There is a magic trick to fix it using standard JPA API only, but I don't know it yet.
Please help.
You are referring to the transaction isolation of JPA transactions. I.e. what is the behaviour of transactions when they access other transactions' resources.
According to this article:
READ_COMMITTED is the expected default Transaction Isolation level for using [..] EJB3 JPA
This means that - yes, you will have problems with the above code.
But JPA doesn't support custom isolation levels.
This thread discusses the topic more extensively. Depending on whether you use Spring or EJB, I think you can make use of the proper transaction strategy.