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++
// [시나리오] 게임 내 순번 ID 발급 (서버 내부, DB)
//
// 우편/거래 로그처럼 사람이 읽는 순번(mail_no)을 부여하려고, 현재 최대값을
// 조회해 +1 한 값을 새 행의 번호로 사용한다. 여러 워커가 동시에 우편을 발송한다.
//
// [요구사항]
// - 각 우편은 유일한 mail_no 를 가져야 한다.
// - 동시 발송에도 번호가 겹치지 않아야 한다.
//
// [과제]
// 아래 CreateMail 을 리뷰하라. (A)(B) 지점의 동작을 근거로 동시 발송이
// 겹칠 때 무슨 일이 생기는지 재현과 함께 설명하고 수정안을 제시하라.
// (mail_no 에는 PK/UNIQUE 제약이 있다고 가정)
#include <cstdint>
#include <string>
struct MailPayload { std::string body; };
struct Db {
// "SELECT COALESCE(MAX(mail_no),0) FROM mail"
int64_t QueryMaxMailNo();
// INSERT; PK/UNIQUE 위반 시 예외
void InsertMail(int64_t mailNo, int64_t receiverId, const MailPayload& p);
};
class MailService {
Db* db_;
public:
int64_t CreateMail(int64_t receiverId, const MailPayload& payload) {
// (A) 현재 최대 번호 조회
int64_t maxNo = db_->QueryMaxMailNo();
int64_t newNo = maxNo + 1;
// (B) 그 번호로 삽입
db_->InsertMail(newNo, receiverId, payload);
return newNo;
}
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.