Spring boot + JPA + Hibernate + PostgreSQL pessimistic_read with JPA native query - java

I need to return one item id from table which has not been processed yet (At given time there can be multiple available but I need to return unique id per request).
I am fetching first record from DB using JPA native query
#Lock(LockModeType.PESSIMISTIC_READ)
#QueryHints({#QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
#Query(value = "SELECT id FROM item WHERE name->> 'name'=:name AND city->> 'city'=:city LIMIT 1",nativeQuery = true)
public String find(#Param("name") String name, #Param("city") String city);
Post that I am changing the status to processed using update query
Returning the ID
The above scenario throws an exception stating "Invalid use of Lock" (As it doesn't support native query and only supports crud operations).
Need help to use PESSIMISTIC_READ using native query for SELECT for UPDATE and SKIP locked row during race condition.

By Adding below line in query solved the issue.
FOR UPDATE SKIP LOCKED
#Query(value = "SELECT id FROM item WHERE name->> 'name'=:name AND city->> 'city'=:city LIMIT 1 FOR UPDATE SKIP LOCKED",nativeQuery = true)
public String find(#Param("name") String name, #Param("city") String city);

Related

JAVA Spring Boot - existsByColumne1AndNotColumn2 Repository query

I am working with Java Spring Boot where I want to create default query to find if a user already exists with the given mobile number and not with the given user id. A raw query is this
SELECT * FROM `user` WHERE mobile = "9898989898" AND user_id != 123
I did found that to check with single column whether the data is exist in that column or not, we can do something like this in Repository class
Boolean ExistWithMobile(String mobile)
This will return true or false if row found with the given mobile number.
The same way I want query similar to above, but this is not working
Boolean existsByMobileAndNotUserId(String mobile, Long userId);
This should return true or false whether this phone number is available with Other userId
I know how can I work with raw queries, as I already mention that in starting of the question, but I want something like this direct way of query, without raw query.
Any help would be appreciated.
if you don't wanna use native sql query, you could use HQL instead.
in your case:
#Query("from User u Where u.mobile = :mob and u.id != :id")
Optional<User> findUserByMobile(#Param("mob") String mobile, #Param("id") long id)
when you call :
Optional<User> user = repo.findUserByMobile(mobile, uid);
if( user.isPresent() ) { ... }
here is doc of #Query in spring data :
Spring Data JPA
Good luck

How to force Hibernate use AND in update query?

I am trying to update a raw by composite primary key by using hibernate.
Hibernate uses the next style for such updates:
update mytable set mycolumn=321 where (left_pk, right_pk) = (123, 456);
Is it possible to force hibernate to use the next style?:
update mytable set mycolumn=321 where left_pk = 123 and right_pk = 456;
Both queries work but with a huge difference (at least in MariaDB).
If we use repeatable read transaction then the first query locks the whole table for updates and the second query locks only the single row for updates.
I would prefer to lock only a single row, so I need to use the second query.
You can go for NamedQueries approach in Hibernate,
For example:
//Create Query
#NamedQueries({ #NamedQuery(name = " YOUR QUERY NAME",
query = "from DeptEmployee where department = :department and emp = :emp") })
// set multiple parameters
query.setParameter("department",department)
.setParameter("emp", emp)
Try giving this a shot.

Will entityManager.createQuery().executeUpdate() execute immediately on DB?

I'm using hibernate jpa. I'm trying to execute an update query and want to tell if the update actually happen or not based on the return value because I may have multiple processes doing the same updates and I only want to continue with the process that successfully update the record. (Relying on mysql return 1 iff the update happen successfully, 0 if nothing changed.)
int update = entityManager.createQuery("update Employee set name = \'xxxx\' where id=1").executeUpdate();
My question is that with default flush mode (AUTO), will this query being executed on the db? (if not, does the return value still make sense?) What about flush mode = COMMIT? Do I need to do entityManager.flush()? (I feel like the query execution will bypass the entityManager so flush doesn't do anything?)
What if I use JPA repository instead of the native query?
#Modifying
#Query("UPDATE Employee SET name = :name WHERE id = :id)
int update(long id, String name)
Will the return value reflects the rows changed in DB or just the persistent context?

hibernate hql - return updated rows id list after execute update query

I'm using Hibernate Query Language(HQL) with Oracle database in my Java spring MVC application. I have write an HQL update query in this way:
String hql = "update " + MyModel.class.getName() + " e set e.field = " + value + " where ..."
//Acquiring session
...
Query query = session.createQuery(hql);
int result = query.executeUpdate();
The executeUpdate() method returns number of updated rows. But I want to get a list of the ids of updated rows after executing the update query. Is there any way of doing this in HQL?
As far as I know there is no such functionality in JPA/Hibernate. But you can create native query and use native SQL. I do not know oracle, but in PostgreSQL I would write :
String sql = "update table set field = :values where ... returning id";
Query query = session.createNativeQuery(sql);
query.setParameter("value", value);
List ids = query.list();
May be oracle have similar functional and this will help you.
Blaze-Persistence, a library that works on top of JPA/Hibernate, adds support for this.
Here some more information about that: https://persistence.blazebit.com/documentation/core/manual/en_US/index.html#returning-from-update-statement

What's the fastest way to check if a row exists in DB using Hibernate & spring?

I need to check if a row exists in a database in a very fast way.
Let's say I've got the primary key.
I found this code snippet in Hibernate's FAQ website:
Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();
I just started using spring, so I have HibernateTemplate object injected into my class.
How do I translate this snippet to work with HibernateTemplate.
Does anyone knows a better/faster way than this ?
Thanks.
Long count = hibernateTemplate.execute(new HibernateCallback<Long>() {
#Override
public Long doInHibernate(Session session) {
return (Long) session.createQuery("select count(someEntity.id) from SomeEntiuty someEntity ...").uniqueResult();
}
});
Hibernate used Integer for count queries before, but now uses Long. Also, note that even if not deprecated, Spring recommends not to use HibernateTemplate anymore and use the Hibernate API directly (using sessionFactory.getCurrentSession()).
Fastest way of checking primary key exist or not in database.
public void exist(Long id) {
Session session = sessionFactory.getCurrentSession();
String queryString = "select 1 from Employee e where e.id= :id";
Query query = session.createQuery(queryString);
query.setParameter("id", 1l);
Integer result = (Integer) query.uniqueResult();
System.out.println(result);
}
Again this also depends on a lot on what engine that you are using MyISAM vs innodb.
select count(col1) from table; will return the number of rows where the column is not null.
select count(*) from table; will return the number of rows.
Depending upon the database that you are using , a select count(*) will be more expensive than reading it from meta data table or system level tables that keep track of the row count.
Just my 2 cents.
Depending upon various other factors like indexes and other information / joins / access privileges this may be faster
SELECT table_rows FROM `information_schema`.`TABLES` where table_schema = 'database_schema_name' and table_name = 'table_name';
I think it's better to get an specific representative field of the first row found (using the PK or at least another indexed field), than counting all of the possible records that would match your search criteria.
If you're using Spring it will throw EmptyResultDataAccessException if no record was found.

Categories