ObjectOptimisticLockingFailureException

Minky·2023년 2월 6일
0

이전에 개인 노션에 정리한 내용을 옮겼습니다

모니터링중, 간혹 발생하는 해당 exception 원인을 분석해 보았다.

코드 분석 전 알아야할 내용

  • 트랜잭션 격리수준 : READ COMMITTED
  • JPA id 생성 전략 : @GeneratedValue(strategy = GenerationType.IDENTITY)
  • chat_room(상담방) / chat_room_timescale(상담지표) : 1:n 관계, cascade = CascadeType.ALL
    @Table(name = "chat_room_timescale")
    public class ChatRoomTimeScale extends BaseEntity {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(nullable = false)
      private Long id;
    
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "chat_room_id", referencedColumnName = "id")
      private ChatRoom chatRoom;
    }
    @Table(name = "chat_room")
    public class ChatRoom extends BaseEntity implements ICacheKey {
    
    	@Id
      	@GeneratedValue(strategy = GenerationType.IDENTITY)
      	@Column(nullable = false)
      	private Long id;
    
    	@OneToMany(mappedBy = "chatRoom", cascade = CascadeType.ALL)
    	private List<ChatRoomTimeScale> chatRoomTimeScales;
    }

JPA 개념

JPA 잊지말아야할 개념

  • 영속성 컨텍스트에 영속화되었다는것, 즉 관리를 받을 수 있는건 id값이 있는, id값이 부여된 객체이다.
  • GenerationType.IDENTITY 생성전략 사용시, persist() 될때 즉시 insert SQL를 실행하고 DB를 통해 식별자를 얻어온다. (보통은 트랜잭션 commit시점에 insert ⇒ 쓰기지연) 💡 아직 커밋된것은 아니므로 다른 트랜잭션은 모른다(?)
  • ObjectOptimisticLockingFailureException
    ERROR o.h.e.j.batch.internal.BatchingBatch@performExecution(132) - HHH000315: Exception executing batch [org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1], SQL: update `chat_room_timescale` set `request_time`=? where `id`=?
    1. 두 개의 서로다른 트랜잭션(스레드)가 동시에 동일한 데이터를 변경하려 할 경우 발생.

      Second Lost Updates Problem (두 번의 갱신 분실 문제)

    2. 존재하지 않는 ID로 레코드를 삭제/업데이트 하려할때 발생

      java - 버전 주석 또는 OptimisticLocking 전략없이 ObjectOptimisticLockingFailureException 가져 오기

  • 식별자가 아닌 필드로 조회를 하면 조회 쿼리를 하기 전에 쓰기지연 저장소에 있던 UPDATE 쿼리를 날리고 그 이후에 조회를 한다.
profile
소통하는 Web Developer가 되고 싶습니다 :)

0개의 댓글