티스토리 뷰

카테고리 없음

MySQL 주문 테이블의 잠금 대기로 등록이 지연될 때 확인할 트랜잭션

생각방 2026. 11. 10. 17:15

목차


    출고 마감에 앞서 주문 연동 담당자가 쇼핑몰에서 들어온 주문과 사내 주문 목록을 대조합니다. 쇼핑몰에는 접수 기록이 있는데 사내 목록에 아직 나타나지 않는 건이 있습니다. 재처리 화면에서 해당 주문을 다시 보내도 저장 응답이 늦어지면, 담당자는 앞선 등록 작업이 끝났는지부터 확인해야 합니다.


    잠금 대기로 등록이 지연될 때 트랜잭션 확인

    이 글은 주문 연동 운영을 바탕으로 구성한 설명용 업무 장면입니다. MySQL 8.4의 InnoDB에서 기다리는 등록 요청과 잠금을 보유한 작업을 연결하는 순서로 살펴봅니다.

    주문 목록에 나타나기 전의 INSERT

    연동 작업이 주문 행을 넣었더라도 트랜잭션을 아직 커밋하지 않았다면, 다른 연결의 일반 조회에서 그 행이 보이지 않을 수 있습니다. 트랜잭션은 관련 DB 변경을 묶어 확정하거나 되돌리는 작업 단위입니다. 주문번호에 UNIQUE 제약조건이 있고 재처리 요청이 같은 키를 넣으려 하면, 앞선 작업의 변경이 확정되거나 취소될 때까지 두 번째 INSERT가 대기할 수 있습니다. MySQL 8.4 — SQL 문장별 InnoDB 잠금

    화면에서 확인한 것은 주문이 아직 조회되지 않고 저장 응답이 늦다는 점입니다. 같은 키로 인한 잠금 대기인지는 DB에서 두 작업의 관계를 확인하고, 주문 연동 기록에서 두 요청이 실제로 같은 주문을 다루는지 대조해야 알 수 있습니다.

    중지 메세지에 대한 두 작업간 관계 확인

    대기 요청과 잠금 보유 작업의 연결

    대기가 이어지는 동안 주문을 기록하는 MySQL 서버에서 다음 조회를 실행합니다. 해당 운영 환경에서 다른 세션의 정보를 볼 수 있는 계정을 사용합니다. 결과가 여러 건이면 오래 기다린 행부터 참고하되, 장애 요청과 맞는 SQL과 테이블을 찾아야 합니다.

    SELECT waiting_pid,
           waiting_trx_id,
           waiting_query,
           blocking_pid,
           blocking_trx_id,
           blocking_query,
           blocking_trx_started,
           blocking_trx_rows_modified,
           locked_table_schema,
           locked_table_name,
           locked_index,
           wait_age_secs
    FROM sys.innodb_lock_waits
    ORDER BY wait_age_secs DESC;

    waiting_pid는 잠금을 기다리는 연결이고 blocking_pid는 그 대기를 일으키는 연결입니다. 각각의 *_trx_id는 그 시점의 트랜잭션을 가리킵니다. locked_table_name과 locked_index로 충돌 대상을 좁힌 뒤 주문번호나 요청 식별자를 연동 로그에서 확인합니다. 인덱스 이름만으로 어느 주문번호가 충돌했는지 확정할 수는 없습니다. MySQL 8.4 — innodb_lock_waits 뷰

    wait_age_secs는 현재 잠금 대기 시간입니다. 저장 화면이 열린 전체 시간과는 범위가 다릅니다. 조회 결과가 비어 있으면 수집 시점에 해당 대기가 끝났을 수 있으니, 요청 로그에 남은 DB 오류와 시각도 함께 봅니다.

    현재 SQL이 비어 있는 잠금 보유 연결

    blocking_query가 NULL이면 해당 연결이 다음 명령을 기다리는 상태일 수 있습니다. 앞선 변경을 아직 커밋하거나 롤백하지 않았다면 잠금은 남을 수 있습니다. 이때는 blocking_trx_started로 연동 작업의 실행 구간을 좁히고, blocking_trx_rows_modified로 변경 행이 있는지 확인합니다. 이 값은 트랜잭션의 변경 행 수이며 주문 건수로 해석할 수 없습니다. MySQL 8.4 — innodb_lock_waits 뷰

    DB에서 앞선 문장을 더 확인할 때는 blocking_pid에 해당하는 performance_schema.threads.PROCESSLIST_ID로 THREAD_ID를 찾습니다. 그 ID의 문장 이력과 연동 로그를 대조하면 주문 저장 작업인지, 같은 연결에서 앞서 수행한 다른 작업인지 구분하는 데 도움이 됩니다. 문장 이력이 남아 있는 범위는 서버 수집 설정에 따릅니다. MySQL 8.4 — 유휴 연결의 잠금 보유 작업 추적

    SQL의 데드락 점검

    잠금 해제 뒤 주문 재처리 기준

    잠금을 보유한 작업을 찾으면 주문 연동 담당자와 함께 정상 완료를 기다릴지, 작업을 취소할지 판단합니다. 판단에 필요한 정보는 처리 중인 주문과 같은 트랜잭션에 묶여 있는 변경입니다. 앞선 작업이 끝난 뒤에는 주문번호로 확정된 데이터와 처리 상태를 조회해 재처리 여부를 정합니다.

    확인한 상태 다음 판단
    앞선 작업이 커밋되어 같은 주문이 조회됨 중복 등록을 보류하고 기존 주문의 처리 상태를 확인합니다.
    앞선 작업이 롤백됐고 주문이 조회되지 않음 대기하던 요청의 최종 결과를 확인합니다. 주문이 여전히 없고 진행 중인 요청도 없을 때 재처리합니다.
    뒤쪽 요청에 DB 잠금 대기 시간 초과가 기록됨 애플리케이션이 트랜잭션을 어떻게 정리했는지 확인하고 재처리 여부를 판단합니다.

    잠금이 풀려도 대기하던 INSERT가 반드시 성공하는 것은 아닙니다. 앞선 작업이 같은 키를 확정하면 중복 키 오류로 끝날 수 있습니다. InnoDB의 기본 설정에서는 잠금 대기 시간 초과가 발생한 문장만 롤백되므로, 그 요청이 앞서 실행한 변경까지 취소됐는지는 애플리케이션의 예외 처리와 DB 설정을 확인해야 합니다. MySQL 8.4 — SQL 문장별 InnoDB 잠금 · MySQL 8.4 — InnoDB 오류 처리

    결론

    재처리 버튼을 누르기 전에 DB의 대기 연결과 잠금 보유 연결을 한 쌍으로 남겨 두면, 담당자가 어떤 작업의 종료를 확인해야 하는지 알 수 있습니다. 같은 유형의 지연이 반복된다면 주문 INSERT부터 커밋까지의 코드에서 외부 응답을 기다리거나 여러 주문을 한 트랜잭션에 묶는 구간을 살펴봅니다. 트랜잭션을 줄일 때는 주문과 함께 확정해야 할 변경의 범위도 확인합니다.

    참고자료