User user = userRepository.findOne(1);
user.age = user.age + 1; // user.age value modify
userService.updateUser(user);
@Transactional
class UserService {
public void updateUser(User user) {
productRepository.findByName("AAA"); // (1)
userRepository.save(user); // (2)
}
}
@Entity
@EntityListener(UserListener.class)
class User {...}
class UserListener{
@PreUpdate
public void onPreUpdate() { ... }
}
When OSIV = true,
(1) line --> @PreUpdate
called /
(2) line --> @PreUpdate
called
When OSIV = false,
(1) line --> @PreUpdate
not called /
(2) line --> @PreUpdate
called
Why does this happen? Why @preupdate called when (1) line executed?
Here is the JPA 2.0 specification:
Keep in mind that @PreUpdate it will always be triggered for all read/write transactions because of the FlushMode on read/write transactions and never on readonly transactions (because of FlushMode.NEVER)
Without OSIV
When you call
updateUser
, then you have a read/write transaction (the outer one) because of@Transactional
.Now,
findByName
is transactional but marked as readonly (by default all finders are readonly). The current transaction is suspended and a new readonly one is performed. That's why (1) line does not trigger@Preupdate
.After that, the current read/write transaction resumes (
save
is not readonly) and the@Preupdate
is triggered.With OSIV
This case there is only one read/write transaction bound to the current request.
findByName
is executed in a read/write transaction, therefore (1) line does trigger @Preupdate