5

For testing the @Version annotation, I am using the following setup to manage persistence:

  • Spring Boot Starter 1.5.3.RELEASE
  • Hibernate 5.2.10.Final
  • Spring Data Envers 1.1.3.RELEASE -> Spring Data JPA 1.11.3.RELEASE

Databases tested:

  • H2
  • PostgreSQL
  • MariaDB
  • Oracle

The entities are utilizing an @Version annotated field which will be incremented on update. One example entity looks like this:

import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Version; @Entity @Table(name = "\"users\"") public class User { @Id private Long id; private boolean active; @Version @Column(nullable = false) private long version = 0L; // getters/setters (not shown) } 

The Spring Data JPA based UserRepository provides custom modifying queries besides the CRUD ones:

import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; public interface UserRepository extends CrudRepository<User, Long> { @Modifying @Query("UPDATE User u SET u.active = false WHERE u.id = ?1") void deactivate(Long id); @Modifying @Query("UPDATE User u SET u.active = false WHERE u.id IN :ids") void deactivateAll(@Param("ids") Long... ids); @Modifying @Query("UPDATE User u SET u.active = false WHERE u.id IN :ids") void deactivateAll(@Param("ids") Iterable<Long> ids); } 

As the version field is not automatically increased for JPQL/HQL queries, this must be done manually by adjusting the custom queries accordingly.

When trying to use the Hibernate specific (non-JPA conforming) VERSIONED keyword (HQL only) to extend the query

@Modifying @Query("UPDATE VERSIONED User u SET u.active = false WHERE u.id = ?1") void deactivate(Long id); 

the generated SQL is not valid indepentently of the database tested, resulting in an error looking something like this (schema name is TEST):

Table "USER0_" not found; SQL statement: update "TEST"."users" set user0_."version"=user0_."version"+1, "active"=0 where ("id") IN (select "id" from "HT_users") [42102-194]

So, how can I update the JPA/Hibernate @Version field in a Spring Data JPA @Modifying @Query query?

2 Answers 2

2

You can add u.version=u.version+1 to the query. The updated @Querys look like this:

import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; public interface UserRepository extends CrudRepository<User, Long> { @Modifying @Query("UPDATE User u SET u.version=u.version+1, u.active = false WHERE u.id = ?1") void deactivate(Long id); @Modifying @Query("UPDATE User u SET u.version=u.version+1, u.active = false WHERE u.id IN :ids") void deactivateAll(@Param("ids") Long... ids); @Modifying @Query("UPDATE User u SET u.version=u.version+1, u.active = false WHERE u.id IN :ids") void deactivateAll(@Param("ids") Iterable<Long> ids); } 

There may be caveats using this. E.g. this will obviously not fail with an OptimisticLockException like updates issued by the EntityManager do (as described here).

Sign up to request clarification or add additional context in comments.

6 Comments

Try to use @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT) instead of incrementing version manually
@JaySmith Thank you very much for the hint, but it seems to me that the Lock annotation cannot be combined with a modifying query like the ones from my example repository. At least I get a pretty self-speaking exception: "java.lang.IllegalStateException: Illegal attempt to set lock mode on a non-SELECT query" when simply adding it as is. The documentation and API docs do not help me here or I'm missing something. Do I have to take anything else into account?
I created hql query with versioned keyword and it works ok. You get error Table "USER0_" not found` . Is it related to versioned keyword? In hibernate docs it is said that you cannot modify version explicitly.
@JaySmith did you use Query annotation for the HQL? What about the JPA settings, e.g. globally quoted identifiers. I will update my question and add some of my missing settings. And you're right, the hibernate docs say it is forbidden to alter the version manually. I will take a look at the Lock annotation again, maybe I'll find a hint there what to do to update the version properly. Actually that's why I asked the question as it is not obvious to me so far. Thanks again for your support!
I didn't use spring data jpa. I created hql query with session.createQuery method.
|
0

As answered the similar question here - try to add VERSIONED keyword after the UPDATE keyword:

@Modifying @Query("UPDATE VERSIONED User...) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.