Issue
Following tutorial on Java Spring, I'm trying to understand how @Transactional work with setters, and from other question/sources, I can't find a beginner-friendly explanation for it.
Let's say I have a user entity with getters and setters:
@Entity
@Table
public class User {
// Sequence set up
private Long id;
private String name;
private String email;
private String password;
// Other constructors, setters and getters
public void setName(String name) {
this.name = name;
}
}
And in the UserService I have a getUserName method:
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public StudentService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public Boolean getName(Long id) {
User user = userRepository
.findById(id)
.orElseThrow(
() -> new IllegalStateException("Invalid id"));
user.setName("new user name"); // Why will this update db?
return true;
}
}
Comming from javascript ORM, we usually update data like this: userRepository.update()
.
With @Transactional annotated, the setter function does update db, is this the spring way of updating data? Can someone help explain in layman term, how the Transactional work with setters under the hood?
Edit:
Without @Transactional
, setter function won't update db, but in
order to mutate db, will have to call userRepository.save(user)
. And from the video, the instructor simply says the Transactional will handle jpql for us, and use setters along with it to update db.
Solution
Firstly, it is the underlying JPA provider (assume it is Hibernate) to be responsible for updating the entity but not Spring. Spring just provides the integration support with Hibernate.
To update an entity loaded from the DB , generally you need to make sure the following happens in order.
Begin a DB transaction
Use
EntityManager
to load the entity that you want to update.The loaded entity is said to be managed by thisEntityManager
such that it will keep track all the changes made on its state and will generate the necessary update SQL to update this entity in (4) automatically.Make some changes to the entity 's state. You can do it through any means such as calling any methods on it , not just restricting to calling it by setter
Flush the
EntityManager
. It will then generate update SQL and send to DB.Commit the DB transaction
Also note the followings:
- Spring provides
@Transactional
which is a declarative way to execute (1) and (5) by annotating it to a method. - By default , Hibernate will call (4) automatically before executing (5) such that you do not need to call (4) explicitly.
- Spring Data JPA repository internally use
EntityManager
to load the user. So the user return from the repository will be managed by this EntityManager.
So in short , @Transactional
is necessary to update the entity. And updating the entity is nothing to do with setter as it just care if there are state changes on the entity in the end , and you can do it without using setter.
Answered By - Ken Chan
Answer Checked By - David Marino (JavaFixing Volunteer)