a native query to trigger a table lock using SQL (Postgres) - java

I would like to make sure that the whole table is locked during my JPA transaction.
As far as i could figure out, there is no JPA Locking Mode to lock the whole table.
My question is, how does a proper Locking Statement look like and how can i combine it with entity managers merge or persist operations?

Actually thanks to the comment the solution was following statement:
getEntityManager().createNativeQuery("LOCK TABLE schemaname.tablename").executeUpdate();
The lock will get removed then the transaction (also the one from hibarnate - actually its the same) is over.

Related

Locking in JpaRepository Java Spring Boot

Is it possible in spring boot to take lock on whole table instead of rows?
So far I saw only EntityManager.lock(*) but this locks on only given records.
I have a situation in which I have to delete all records of a table and fill that table again with records, For this transaction, I want to take a lock on the table so that no other process reads from this table.
I am using JpaRepository.
Use entityManager.lock(user,LockModeType.PESSIMISTIC_WRITE);
It will take lock on whole table and no other transaction can read, update or delete from the table.
Hope it helps..!!

Hibernate update query confusion

I am running java application with multiple threads those will query from oracle database and if condition meets it will update row. But there are high chances that multiple threads gets same status for a row and then multiple thread try to update same row.
Lets say if status is "ACCEPTED" for any row then update it to "PROCESSING" status and then start processing, But processing should be done by only one thread who updated this record.
One approach is I query database and if status is "ACCEPTED" then update record, I need to write synchronized java method, but that will block multi-threading. So I wanted to use sql way for this situation.
Hibernate update method return type is void. So there is no way I can find if row got updated now or it was already updated. Is there any Select for Update or any locking thing in hibernate that can help me in this situation.
You can very well make use of Optimistic Locking through #Version.
Please look at the post below:
Optimistic Locking by concrete (Java) example
I think that your question is related to How to properly handle two threads updating the same row in a database
On top of this I woud say on top of the answer provided by #shankarsh that if you want to use a Query and not the entitymanager or the hibernate session you need to include the version field in your query like this:
update t.columntoUpdate,version = version + 1 from yourEntity where yourcondition and version = :version
This way the update will succeed only for a particular version and all the concurent updates will not update anything.

How to lock a database row with JPA

In the following code snippet, the whole table is locked instead of a single row:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void myInsertMethod(MyEntity myEntity) {
/*1 this doesn't works*/
manager.lock(myEntity,LockModeType.READ);
manager.persist(myEntity);
/* and this works but I dont know is it what i want or not...*/
manager.persist(myEntity);
manager.lock(myEntity,LockModeType.READ);
}
I think that the correct code will be the following, but it doesn't work
/*lock entire table for select*/
manager.lock(MyEntity.class.LockModeType.READ);
/* and after locking table persist code */
manager.persist(myEntity);
Please tell me how I can do this job and suggest me a good article for learning this issue.
The LockModeType.READ is equals to OPTIMISTIC, meaning Hibernate tries to verify the optimistically locked entity version before transaction completion.
Aside from the possible race condition, this won't help you too much. In your case, the entity acquires an implicit lock when the flush operation issues an INSERT statement.
Because entities have unique PRIMARY KEYS, you shouldn't even care too much about locking the rows, since you can't have two transactions inserting the same row. The concurrency control is more suitable for UPDATE/DELETE statements, and even then, you don't need to lock an entire table (just the records you want to change).

Table level Lock in Hibernate

I use Hibernate version 4. We have a problem in batch process. Our system works as below
Select set of records which are in 'PENDING' state
Update immediately to 'IN PROGRESS' state
Process it and update to 'COMPLETED' state
The problem when we have two servers and executing at same time, we fear of having concurrency issue. So we would like to implement DB Lock for first two steps. We used query.setLockOptions(), but it seems not working. Is there any other to have table level lock or Row level lock till it completes select and update. Both are in same session.
We have options in JDBC that LOCK TABLE <TABLE_NAME> WRITE. But how do we implement in hibernate or is it possible to implement select..for update in hibernate?
"Select ... for update" is supported in Hibernate via LockMode.UPGRADE which you can set in, for example, a NamedQuery.
But using application/manual table-row locking has several drawbacks (especially when a database connection gets broken half-way a transaction) and your update-procedure can do without it:
Start transaction.
update table set state='PENDING', server_id=1 where state='IN PROGRESS';
Commit transaction
select from table where state='PENDING' and server_id=1;
[process records]
Each server must have a unique number for this to work, but it will be less error-prone and you let the DBMS do what it is supposed to be good at: isolation (see ACID).

How to code optimistic and pessimistic locking from java code

I know what optimistic and pessimistic locking is, but when you write a java code how do you do it? Suppose I am using Oracle with Java, do I have any methods in JDBC that will help me do that? How will I configure this thing? Any pointers will be appreciated.
You can implement optimistic locks in your DB table in this way (this is how optimistic locking is done in Hibernate):
Add integer "version" column to your table.
Increase the value of this column with each update of corresponding row.
To obtain lock, just read "version" value of the row.
Add "version = obtained_version" condition to where clause of
your update statement. Verify number of affected rows after update.
If no rows were affected - someone has already modified your entry.
Your update should look like
UPDATE mytable SET name = 'Andy', version = 3 WHERE id = 1 and version = 2
Of course, this mechanism works only if all parties follow it, contrary to DBMS-provided locks that require no special handling.
Hope this helps.
Suppose I am using Oracle with Java, do I have any methods in JDBC that will help me do that?
This Oracle paper should provide you with some tips on how to do this.
There are no specific JDBC methods. Rather, you achieve optimistic locking by the way that you design your SQL queries / updates and where you put the transaction boundaries.

Categories

Resources