SpringData JPA
StaleObjectStateException은 주로 JPA(hibernate)에서 동시성 문제로 발생하는 예외
특히 낙관적 락(Optimistic Locking)을 사용하고 있는 엔티티에서 발생할 가능성이 높다
@Version 필드를 사용하여 낙관적 락을 적용하면 데이터 충돌을 감지할 수 있습니다.
@Entity
public class ExampleEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version // 버전 필드 추가
private Integer version;
private String name;
}
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT e FROM ExampleEntity e WHERE e.id = :id")
ExampleEntity findByIdWithLock(@Param("id") Long id);
@Transactional
public void updateEntityWithLock(Long id, String newName) {
ExampleEntity entity = entityRepository.findByIdWithLock(id);
entity.setName(newName);
entityRepository.save(entity);
}
- PESSIMISTIC_WRITE를 사용하면 데이터를 가져오는 순간 다른 트랜잭션에서 해당 데이터 수정이 차단된다.
- 단, 트랜잭션이 길어질 경우 성능 저하와 데드락 위험이 있으므로 주의해야 함.
만약 Hibernate의 세션이 오래 유지되면서 StaleObjectStateException이 발생하는 경우, 명시적으로 세션을 갱신하는 것도 방법이 될 수 있다
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void refreshEntity(Long id) {
ExampleEntity entity = entityManager.find(ExampleEntity.class, id);
entityManager.refresh(entity); // 세션 동기화
}