9. SELECT-후-INSERT 중복 생성 레이스(고유 제약/ON CONFLICT 부재) (C#)

난이도 하 해설 보기 →

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

결함 코드 · C#
// 시나리오: 길드 생성 API. 길드 "이름"은 서버 전체에서 유일해야 한다(중복 금지).
// 구현은 먼저 같은 이름이 있는지 SELECT 로 확인하고, 없으면 INSERT 한다.
// 동시에 여러 플레이어가 같은(혹은 인기) 이름으로 길드를 만들 수 있다.
//
// 요구사항:
//   - 같은 이름의 길드가 두 개 이상 생기면 안 된다.
//   - CreateGuild 는 여러 요청 처리 스레드/인스턴스에서 동시에 호출될 수 있다.
//   - guild 테이블에는 (참고) name 컬럼이 있고, 현재 스키마상 별도 제약은 없다.
//
// 과제: (A)(B) 지점을 검토하라. 동시 호출 시 같은 이름의 길드가 둘 생길 수 있다.
//       어떤 인터리빙에서 그런지 밝히고, 중복을 확실히 막도록 고쳐라.

using System.Threading.Tasks;

public interface IDb
{
    Task<bool> ExistsAsync(string sql, string arg);       // SELECT
    Task<int>  ExecAsync(string sql, string a, ulong b);  // INSERT (영향 행 수)
}

public sealed class GuildRepo
{
    private readonly IDb _db;
    public GuildRepo(IDb db) => _db = db;

    public async Task<bool> CreateGuildAsync(string name, ulong ownerId)
    {
        if (await _db.ExistsAsync("SELECT 1 FROM guild WHERE name=@n LIMIT 1", name)) // (A)
            return false;                                                             // 이미 존재 → 거부
        await _db.ExecAsync("INSERT INTO guild(name, owner_id) VALUES(@n, @o)",        // (B)
                            name, ownerId);
        return true;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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