I faced a problem and could not understand the reason. When i update a column of the entity and then perform a select query in the same transaction, hibernate reflects the changes to database. However, transactional method is not completed yet. Scenario is too long and i try to explain it in simple way.
The User Entity
public class User {
@Id
private Long id;
private String name;
private Long depertmantGuid;
}
Here is the Services
@Transactional
@Service
public class Service1 {
@Autowired
private Service2 service2;
public void update() {
// other logics
service2.update();
}
}
@Service
public class Service2 {
@Autowired
private UserService userService;
public void update() {
// other logics
userService.update();
}
}
@Service
public class UserService {
public void update() {
User user = userRepo.findByName("user1");
// there are lots of business logic.
user.setName("USER1");
userRepo.save(user);
userRepo.findByDepartmentGuid(1234L);
throw new RuntimeException("to run rollback mechanisim");
}
}
@Repository
public interface UserRepo extends JpaRepository<User, Long> {
User findByName(String name);
List<User> findByDepartmentGuid(Long guid);
}
the code is simple. When i call service1.update()
method. it calls service2
then calls userService
. The UserService
updates the user-row.
When userRepo.findByDepartmentGuid(1234L);
line worked, the transaction still open and why hibernate commits the changes. I debugged the code and keep cursor on the line userRepo.findByDepartmentGuid(1234L);
the value is "user1" in oracle database, after the line which userRepo.findByDepartmentGuid(1234L);
is worked the value is "USER1" in database. Also, throw exception does not work to roll it back.
How can i fix this situation?
Hibernate has 4 different flush modes;
After the 3.3.x version, Hibarnate accepted AUTO flush mode to avoid dirty data. For example; If you have an update operation in the relevant transaction before the select query, hibernate will first run the update query and then run the select query. Thus, dirty data will not be created.
If you don't want this situation to occur, you should set a flush mode less than 10(FlushMode.AUTO).
So you need to change your flush mode of your hibernate inside properties/yaml file. You can use this settings for your problem, and it will work.
spring.jpa.properties.org.hibernate.flushMode = COMMIT