I'm using Spring boot 2.7.0
And have the next entities in simple:
@Getter
@Setter
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version
private Long version;
private String name;
}
@Getter
@Setter
@Entity
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
Account account;
private String message;
}
and jpa repositories:
@Repository
public interface AccountRepository extends JpaRepository<Account, Long> {
}
@Repository
public interface EventRepository extends JpaRepository<Event, Long> {
Page<Event> findAllByAccount(Account account, Pageable pageable);
}
In short I call
eventRepository.findAllByAccount(accountRepository.findById(1), PageRequest.of(1,10));
Problem is every call of last code increases the version field of Account
by 1. So question is why? I don't call any update or save method.
And additionally the result of this behaviour is calling of method needs
@Transactional(readonly=false)
Otherwise if I write readonly=true
that throws cannot execute UPDATE in a read-only transaction
ADDED:
full code of usage:
@Transactional
public Page<Event> events(Long accountId, int page) {
return eventRepository.findByAccount(findById(accountId), PageRequest.of(page, PAGE_SIZE));
}
@GetMapping("/events")
public List<EventResponse> listEvents(@RequestParam(value = "max", defaultValue = "0") int page) {
return eventService.events(1L, page).stream().map(EventResponse::of).toList();
}
CodePudding user response:
It looks like hibernate is deriving lockMode type as either of WRITE
or OPTIMISTIC_FORCE_INCREMENT
or PESSIMISTIC_FORCE_INCREMENT
based on isolation level of your database. As per reference hibernate decides this pessimistic locking by its own based on database you use.
As per doc, if lockmode type is either of what I mentioned above, Version
will get automatically incremented even if you haven't changed anything i.e. even if you haven't do any update or save.
Please check database isolation level & based on that you might get an idea about this.
Edit: as you explicitly setting lockmode as write so my answer validates that because of WRITE mode, your version got incremented automatically.
CodePudding user response:
The problem should be related in the code which is using the result of the find.
If you're modifying entities under a transaction they're going to be modified at the end of the method, when Spring in this case is going to close the transaction. In this part when transaction ends, the JPA provider (for example hibernate) aligns the relative entity record into the database with the 'java entity object' by an update.
CodePudding user response:
I'm sorry. After trim all my code to the posted and debug I found my mistake:
In the begin I was retrieving Account in another method by .lock(Long)
method instead of .findById(Long)
lock method is below:
@Lock(LockModeType.WRITE)
@Query("from Account where id = :id")
public Optional<Account> lock(Long id);