JPA - how to replicate update versioned query of Hibernate in openjpa - java

I'm trying to replicate the behavior of "update versioned" of Hibernate in Openjpa:
em.createQuery("update versioned MyEntity m set m.otherEntity=null where m.otherEntity=:otherEntity).setParameter("otherEntity", otherEntity).executeUpdate();
I tried the same query in openjpa but i'm getting a error for this query (it takes the "versioned" as a alias), so its clearly a HQL feature.

Hibernate spec:
In keeping with the EJB3 specification, HQL UPDATE statements, by default, do not effect the version or the timestamp property values for the affected entities. However, you can force Hibernate to reset the version or timestamp property values through the use of a versioned update. This is achieved by adding the VERSIONED keyword after the UPDATE keyword.
so HQL has the option to use the update versioned to reset version
however in OpenJpa:
Bulk update maps directly to a database update operation, bypassing optimistic locking checks. Portable applications must manually update the value of the version column, if desired, and/or manually validate the value of the version column.

Related

Spring JPA: Update without existing Id?

I am using Spring-Boot and JPA.
For saving and also updating a record there is the one method save of CrudRepository.
I use a generated long id for primary key of my record.
Now I need to update a already existing record. That will fail with an duplication exception if the primary key id does not
match the value that is already in the database. If no id is given JPA would assume an insert and that fails because the old record already exists.
So what is the best strategy for that?
I do not want to look for the id of the existing record before doing a save for updating my record.
Is there some default value for id that I an use for marking it for update instead of insert?
I don't think Hibernate has such functionality. Some databases support this with their native capabilities (insert ignore in MySQL or on conflict do nothing in Postgres), but you'd have to write SQL yourself. And some databases don't have this feature at all.
Probably, the only way to do this with Hibernate is to handle constraint violation exceptions. Note though if it happens, you may not be able to proceed with the transaction/session since Hibernate warns you that Session/EntityManager can't be further used reliably if it threw an exception.

Hibernate optimistic locking and external programs

I have a progam using hibernate #Version annotation to do optimistic locking.
I want to update a row on the database without doing it via hibernate.
Is it possible to simply increase the value in the column in my DB-Update script and will hibernate then follow the right behavior (throw an exception since the version has changed)?
Yes, it should be possible to increment the version number externally and hibernate will throw an exception if you try and save with an out of date version number.
If you are not seeing that behaviour, you should look into the "hibernate.jdbc.batch_versioned_data" property in your hibernate configuration.
See Hibernate saves stale data with hibernate.jdbc.batch_versioned_data for more info.

Replace single entity in query cache from JPA/Hibernate/EclipseLink?

We need to cache the results of a query; the query returns the whole table of a database. The problem is that the database is changed externally by other application; the Java application making the query is notified with the exact primary key of the row changed.
Is it possible to replace only the changed element from the query cache, not the whole list?
Is this the 1st level cache (from EntityManager) 2nd level Cache (from EntityManagerFactory) or a different cache?
If it is possible can this be done from JPA?
entityManager.refersh(entity);
or is this query cache the 2nd level JPA cache:
entityManagerFactory.getCache().evict(cls, primaryKey);
or only possible through Hibernate/EclipseLink API?
If is not possible, in order to achieve this, would calling entityManager.find() on all elements do it?
I haven't find anything useful neither in Hibernate documentation nor in EclipseLink documentation. Hibernate supports regions and refreshing only regions, but we need entity-level refresh granularity.
Later edit to clarify my findings.
Following the link posted by #Chris in the comment I have found out that what I wanted is actually supported by EclipseLink but only for Oracle Database (there is possible to implement own handler for other vendors; but the call from database is not standardized and differs from vendor to vendor). I have not found if Hibernate supports this or not.
Anyhow the query cache from EclipseLink had some very poor performance compared with Spring Cache (based on CocurrentMap) or with custom based cache so will remain with Spring Cache or Custom Cache over Spring Jdbc.
EntityManager.refresh() is what you want - it refreshes the entity from what is in the database. This should also update the entity in the shared cache if you are not in a transaction, otherwise you may need to use the entityManagerFactory.getCache().evict(cls, primaryKey); as well to clear the second level shared cache so it can be read into it as well later on.

Creating an UPDATE RETURNING query in Hibernate

In Oracle we can create an update query that will return the updated record using the RETURNING clause.
Is there similar functionality in Hibernate?
Apart from database-generated values there is obviously no need for Hibernate to return the updated instance because the object passed to Session.saveOrUpdate() is the updated instance. Database-generated values (sequence, trigger, defaults, etc.) will be set after Session.saveOrUpdate if they are accordingly annotated (or defined in a XML mapping file).
For identifier values use the JPA #javax.persistence.GeneratedValue annotation in conjunction with the JPA #javax.persistence.Id annotation. For simple properties use the native Hibernate #org.hibernate.annotations.Generated annotation (afaik there is no according JPA annotation).
How generated identifier values are retrieved by Hibernate depends on the generation strategy and/or the database dialect. For simple properties Hibernate executes an additional SELECT by id statement after the INSERT or UPDATE.

SQL Server exclusive row lock (XLOCK ROWLOCK) using Spring Transactions using Hibernate

I am attempting to do a select on a row and update the value. While I do this I need exclusive access to the row. In other words, no other process (inside or outside the VM), should be able to read the row until after I update the row. The current value should not be "selectable". I have tried the following transaction annotation.
#Transactional(isolation = Isolation.SERIALIZABLE, readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class, timeout=960)
This definitely works within the Spring context, but while putting a sleep statement in the middle of the transaction, I'm still able to select the current row value using a database tool.
Is there a way to get a XLOCK/ROWLOCK (whichever is the appropriate) using Spring/Hibernate?
Versions:
Spring: 3.0.5.RELEASE
Hibernate: 3.6.3.Final
JTDS: 1.2.4
If I can't use Spring/Hibernate, a link to a JTDS example would be much appreciated.
Thank you.
SERIALIZABLE isolation level allows other transactions to read data, but not to modify. So you need to explicitly SELECT ... FOR UPDATE (in Hibernate: Query#setLockMode(LockMode.UPGRADE)).
Use explicit locking with the Hibernate. There is more information here.
However, I think you have to think once more time - do you really need the pessimistic lock? In most cases optimistic lock works better, and hibernate supports versioning very well.

Categories