How long hibernate locks table during select? - java

Suppose a Criteria is created and then method Criteria.list() is called. It returns N results from table MyTalbe (there is not joins for simplicity). So how long hibernate lock records in MyTable? Does it lock all selected rows until all iterated? Or it lock rows untill session is opened (if yes when it s closed if I do not invoke close on session)?
Note
Database is MySql.

Hibernate does not lock the tables after a select. If you need to block for a particular reason you need to do explicitly.

Related

Does PESSIMISTIC_WRITE lock the whole table?

Just to be sure that I correctly understand how things work.
If I do em.lock(employee, LockModeType.PESSIMISTIC_WRITE); - will it block only this entity (employee) or the whole table Employees?
If it matters, I am talking about PostgreSQL.
It should block only the entity.
PostgreSQL hibernate dialect adds for update in case of write locks:
https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java#L549
(newer versions just use the same implementation)
for update is treated row-wise by PostgreSQL:
https://www.postgresql.org/docs/9.5/static/explicit-locking.html
FOR UPDATE causes the rows retrieved by the SELECT statement to be
locked as though for update. This prevents them from being locked,
modified or deleted by other transactions until the current
transaction ends. That is, other transactions that attempt UPDATE,
DELETE, SELECT FOR UPDATE, SELECT FOR NO KEY UPDATE, SELECT FOR SHARE
or SELECT FOR KEY SHARE of these rows will be blocked until the
current transaction ends; conversely, SELECT FOR UPDATE will wait for
a concurrent transaction that has run any of those commands on the
same row, and will then lock and return the updated row (or no row, if
the row was deleted).

(UPDLOCK, ROWLOCK) locks whole table even tough only 1 row is selected

Inside our Java application we are using a SQL Server statement to pause some processes.
This is the SQL statement:
SELECT * FROM MESSAGES WITH (UPDLOCK, ROWLOCK)
WHERE MESSAGES.INTERNAL_ID IN ('6f53448f-1c47-4a58-8839-e126e81130f0');
The UUIDs in the IN clause changes of course from run to run.
This the Java code we use for locking:
entityManager.createNativeQuery(sqlString).getResultList()
The above SQL statement returns only one row. Unfortunately it seems that the whole table gets locked. The result is that all processes are locked even though none or only some should be blocked.
Why is the whole table locked even though I specify UPDLOCK?
Additional information:
MESSAGES.INTERNAL_ID is NVARCHAR(255) which is not nullable.
Otherwise there is no constraint on the column.
The isolation level is READ_COMMITTED.
This is because your MESSAGES.INTERNAL_ID is not a key. Once row is locked you cannot read it and check it's value. Try to create a primary key on this column.
If it's impossible, create INDEX on it and rewrite your query:
SELECT MESSAGES.INTERNAL_ID FROM MESSAGES WITH (UPDLOCK, ROWLOCK)
WHERE MESSAGES.INTERNAL_ID IN ('6f53448f-1c47-4a58-8839-e126e81130f0');
MSDN says:
Lock hints ROWLOCK, UPDLOCK, AND XLOCK that acquire row-level locks
may place locks on index keys rather than the actual data rows. For
example, if a table has a nonclustered index, and a SELECT statement
using a lock hint is handled by a covering index, a lock is acquired
on the index key in the covering index rather than on the data row in
the base table.

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

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.

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 do I lock database records from Java?

I'm developing a database program in Java with dbf. I need to know how to lock the database records from the Java side.
Example: we have a database table cheques with 5 records in the table (record 1 through 5). There are 2 users, user-1 and user-2. user-1 accesses record 1 and user-2 tries to access record 1 at the same time. I want to lock record 1 to prevent access to that record by user-2 while user-1 is accessing it. How do I do this in Java?
In case of MySQL, you can use, SELECT FOR UPDATE statement for locking the records. Lock will not be released until the transaction completes or rolls back.
More on the same here.
It depends on the environment you are working on. for a container managed transaction your container manages the transactions for you and all you have to do is to set the Lockmode to lockmode.write. What this does is that it blocks all write access to the class methods while userA is accessing record 1. On the other hand for a stand alone application you can just add Synchronization key word to your method to control concurrent access. I hope this helps.
Not every database supports per-record locking.
Generally, if you are in EE environment, you can use JPA EntityManager#find() method to lock certain record.
Full usage will be like that
// EntityManager em;
YourClass obj = em.find(YourClass.class, primaryKey, LockModeType.WRITE);
// do something
em.merge(obj);
After transaction commit the record(s) will be released.
In non-EE environment, as Darshan Mehta said, connection.createStatement().execute("SELECT * FROM table FOR UPDATE") will be the solution.

Categories

Resources