Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring data JPA native query skip locked

I want to execute a SKIP LOCKED query on Oracle using Spring Data JPA, so I tried the following:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "SELECT * FROM User WHERE ID=?1 FOR UPDATE SKIP LOCKED", nativeQuery = true)
User findOne(UUID id);

I tried the above and found that the generated query contains FOR UPDATE, but not SKIP LOCKED (below is the generated query from logs):

select ent0_.column1 as name, ent0_.CREATED_DATE as CREATED_2_33_0_ from TABLE_NAME alias_name where ent0_.column1=? for update

If I remove @Lock from the query method, the generated query does not even have FOR UPDATE.

Please suggest how I can generate a query with FOR UPDATE SKIP LOCKED, as required.

like image 902
Ayan Avatar asked Sep 14 '17 00:09

Ayan


People also ask

How can we avoid optimistic locking in JPA?

The OptimisticLockType. NONE disables the default optimistic locking mechanism for the TestEntity . However, that would only be useful if you inherited the @Version property from a base class which is annotated with @MappedSuperclass or @Inheritance .

What is skip locked?

The SKIP LOCKED DATA option allows a transaction to skip rows that are incompatibly locked by other transactions when those locks would hinder the progress of the transaction. Because the SKIP LOCKED DATA option skips these rows, the performance of some applications can be improved by eliminating lock wait time.

What is for update skip locked?

The SKIP LOCKED clause improves the scalability of applications that attempt to concurrently update the same set of rows in a table. It eliminates wait time for TX locks. Consistency and isolation are preserved.

How do you handle a pessimistic lock exception?

PessimisticLockException indicates that obtaining a lock or converting a shared to exclusive lock fails and results in a transaction-level rollback. LockTimeoutException indicates that obtaining a lock or converting a shared lock to exclusive times out and results in a statement-level rollback.


2 Answers

You can assing -2 to timeout value so that 'skip locked' will be used whenever possible.

PESSIMISTIC_WRITE with a javax.persistence.lock.timeout setting of -2

UPGRADE_SKIPLOCKED

The lock acquisition request skips the already locked rows. It uses a SELECT …​ FOR UPDATE SKIP LOCKED in Oracle and PostgreSQL 9.5, or SELECT …​ with (rowlock, updlock, readpast) in SQL Server.

public interface MyRepository extends CrudRepository<MyEntity, Long> {

    /**
     * The lock acquisition request skips the already locked rows.
     * It uses a SELECT …​ FOR UPDATE SKIP LOCKED in Oracle and PostgreSQL 9.5,
     * or SELECT …​ with (rowlock, updlock, readpast) in SQL Server.
     */
    String UPGRADE_SKIPLOCKED = "-2";

    @Lock(value = LockModeType.PESSIMISTIC_WRITE) // adds 'FOR UPDATE' statement
    @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = UPGRADE_SKIPLOCKED)})
    MyEntity findFirstByStatus(String status);

}

By doing like this, the select query will have select ... for update skip locked

https://docs.jboss.org/hibernate/orm/5.0/userguide/html_single/chapters/locking/Locking.html

like image 72
Muatik Avatar answered Sep 24 '22 16:09

Muatik


Add:

@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="-2")})

like image 34
wwadge Avatar answered Sep 25 '22 16:09

wwadge