[Laravel] beginTransaction, lockForUpdate 활용 (일관성, 동시성) with. ORM

2024. 8. 12. 17:49PHP

[문제 상황]

특정 endPoint에 거의 동시간(1초 이내 시간) 통신요청이 들어와 DB에 중복적인 데이터가 처리됨

 

[문제 당시 코드]

단순한 upsert 코드였지만 1초 이내에 아래 로직을 실행 시 동일한 pk_id를 가진 행이 실행 수 만큼 생성이 되었습니다.

<?php
	DB::beginTransaction();
	try {
    	OrderTradeData::updateOrCreate(['pk_id' => $pkId], [$upsertVo]);
       	DB::commit();
    } catch (Exception $ee) {
        DB::rollBack();
    }

 

transaction으로 해당 로직을 묶었지만 transaction은 일관성을 유지할 뿐 선택 된 행에 대해 동시성 문제를 해결하지 못하는 상황이 연출되었습니다.

 

[해결 코드]

<?php
	DB::beginTransaction();
	try {
    	OrderTradeData::lockForUpdate()->updateOrCreate(['pk_id' => $pkId], [$upsertVo]);
       	DB::commit();
    } catch (Exception $ee) {
        DB::rollBack();
    }

 

lockForUpdate는 transaction안에서만 작동을 하며 lockForUpdate로 선택된 사용자 레코드는 해당 트랜젝션이 완료될 때까지 다른 트랜잭션는 대기 상태로 만들어 동시성 문제를 방지하게 합니다.

좋아보이지만 과도한 사용은 데드락이나 성능에 이슈를 발생시켜 참고하여 사용해야겠습니다.

 

'PHP' 카테고리의 다른 글

락 전략 with Laravel  (0) 2024.10.21
DTO DAO 정리 with 라라벨  (0) 2023.04.21
라라벨 서비스컨테이너와 서비스프로바이더 with DIP  (0) 2023.03.17
라라벨 가바지 컬렉션 처리  (0) 2023.03.17
Eloquent ORM 이란  (0) 2022.12.14