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++
// 시나리오: 길드 생성 API. 길드 "이름"은 서버 전체에서 유일해야 한다(중복 금지).
// 구현은 먼저 같은 이름이 있는지 SELECT 로 확인하고, 없으면 INSERT 한다.
// 동시에 여러 플레이어가 같은(혹은 인기) 이름으로 길드를 만들 수 있다.
//
// 요구사항:
// - 같은 이름의 길드가 두 개 이상 생기면 안 된다.
// - createGuild 는 여러 요청 처리 스레드/프로세스에서 동시에 호출될 수 있다.
// - guild 테이블에는 (참고) name 컬럼이 있고, 현재 스키마상 별도 제약은 없다.
//
// 과제: (A)(B) 지점을 검토하라. 동시 호출 시 같은 이름의 길드가 둘 생길 수 있다.
// 어떤 인터리빙에서 그런지 밝히고, 중복을 확실히 막도록 고쳐라.
#include <string>
#include <cstdint>
// DB 접근 인터페이스(드라이버가 구현). exists=SELECT, exec=INSERT/DDL
struct Db {
bool exists(const std::string& sql, const std::string& arg);
void exec(const std::string& sql, const std::string& a, uint64_t b);
};
class GuildRepo {
public:
explicit GuildRepo(Db& db) : db_(db) {}
bool createGuild(const std::string& name, uint64_t ownerId) {
if (db_.exists("SELECT 1 FROM guild WHERE name=? LIMIT 1", name)) // (A)
return false; // 이미 존재 → 거부
db_.exec("INSERT INTO guild(name, owner_id) VALUES(?, ?)", // (B)
name, ownerId);
return true;
}
private:
Db& db_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.