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.
Related
I have a java spring boot application that use hibernate as ORM. The database is an Azure SQL Server.
I've enabled the setShowSql on vendor adapter configuration.
When I want to find objects, I used the TypedQuery's methods setFirstResult and setMaxResults and than invoke the getResultList method.
The query printed in the console doesn't contains the OFFSET and ROW FETCH clauses and it seems that Hibernate first retrieve all result and than apply the pagination on the resulted list.
This obviously causes performance issues.
Where am I doing wrong?
Below I report the sample code I used.
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
...
query.getResultList()
The only time Hibernate will explicitly include the OFFSET and FETCH clauses under a SQL Server dialect will be when the following conditions are met:
You must use org.hibernate.dialect.SQLServer2012Dialect or any future 2012+ version.
Your query must include an ORDER BY clause.
Your query is not executing a TOP clause query.
The SQLServer2012Dialect uses a customized LimitHandler implementation called SQLServer2012LimitHandler that you can see here that explicitly handles this use case or otherwise falls back to the old behavior.
If both of the requirements above are being met but the logic is still fallig back to the old behavior for some reason, then it's a bug. In that case, you probably should update HHH-12152 with a test case so we can fix it.
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.
Consider a scenario- 2 applications accessing/updating a single database. one of the applications is using hibernate & has got some records from db, will now process them & save it back. But before it saves, the same set of records is updated by the other application. What will happen in this scenario?
Will hibernate throw an error on saving ? or hibernate will have the intelligence to sync the updated records?
The hibernate will throw StaleObjectException. Here is why.
Hibernate uses optimistic locking to handle database concurrency. A StaleObjectExceptionis thrown if the data to be updated is modified by another transaction before current transaction commits the changes.
EDIT:
and how does hibernate identify that the state of object in memory is stale?
Hibernate uses a version field to track the changes to the entity. This version field updated on every commit. Now if the version number just before commit does not match the version number when the entity was read at the beginning of transaction,StaleObjectException is thrown.
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.
I have situation in which I read a record from a database. And if everything is ok I'll modify few properties and commit transaction.
But in situations two threads do the same, they will update the same record.
How to make it in hibernate?
You can use optimistic locking: give entities a version and let it throw an exception and try again later if the version isn't the same because something else (other thread, other node in a cluster or even some independant sql script that bothers to update the version) changed the same entity.
Or you can use pessimistic locking: really lock the entities in the database.
See the Transactions and Concurrency chapter in the hibernate documentation for more details.