21. SELECT MAX(id)+1 방식 순번 발급의 경합 (C#)

난이도 하 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// [시나리오] 게임 내 순번 ID 발급 (서버 내부, DB)
//
// 우편/거래 로그처럼 사람이 읽는 순번(mail_no)을 부여하려고, 현재 최대값을
// 조회해 +1 한 값을 새 행의 번호로 사용한다. 여러 워커가 동시에 우편을 발송한다.
//
// [요구사항]
//  - 각 우편은 유일한 mail_no 를 가져야 한다(중복/건너뜀 방지).
//  - 동시 발송에도 번호가 겹치지 않아야 한다.
//
// [과제]
//  아래 CreateMail 을 리뷰하라. (A)(B) 지점의 동작을 근거로, 동시 발송이
//  겹칠 때 무슨 일이 생기는지 재현과 함께 설명하고 수정안을 제시하라.
//  (Insert 는 mail_no 에 PK/UNIQUE 제약이 있다고 가정)

using System.Threading.Tasks;

public class MailService
{
    private readonly IDb _db;

    public async Task<long> CreateMail(long receiverId, MailPayload payload)
    {
        // (A) 현재 최대 번호 조회
        long maxNo = await _db.QueryScalar<long>(
            "SELECT COALESCE(MAX(mail_no), 0) FROM mail");

        long newNo = maxNo + 1;

        // (B) 그 번호로 삽입
        await _db.Execute(
            "INSERT INTO mail(mail_no, receiver_id, payload) VALUES(@n, @r, @p)",
            new { n = newNo, r = receiverId, p = payload });

        return newNo;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.