Vì entity lấy ra từ repository đang ở trạng thái managed trong persistence context, và Hibernate có cơ chế dirty checking tự động.
@Transactional
public void deactivate(Long id) {
User user = userRepository.findById(id).orElseThrow();
user.setActive(false); // không gọi save() nhưng UPDATE vẫn chạy
}Cơ chế: khi load entity, Hibernate giữ lại một snapshot giá trị các thuộc tính. Tại thời điểm flush (trước khi commit, hoặc trước một truy vấn có thể bị ảnh hưởng), nó so từng thuộc tính của entity managed với snapshot; thuộc tính nào lệch thì sinh câu UPDATE tương ứng.
Hệ quả cần biết:
- Snapshot khiến persistence context tốn khoảng gấp đôi bộ nhớ so với số entity đang quản lý; load hàng chục nghìn entity trong một transaction là chỗ hay bị chậm.
- Entity detached (lấy từ transaction khác, hoặc deserialize từ request) không được dirty check — muốn ghi phải merge/save.
- Sửa nhầm một entity managed sẽ ghi xuống DB dù bạn không có ý định đó. Đây là lý do không nên dùng entity làm DTO nhận request.