Skip to main content
Version: 1.0.0

트랜잭션

트랜잭션은 여러 데이터베이스 작업을 하나의 원자적(Atomic) 단위로 묶어 실행하는 기능입니다. 트랜잭션 내의 모든 작업은 전부 성공하거나 전부 실패합니다.

언제 사용하나요?​

  • 재화 거래: 골드 차감과 아이템 지급이 동시에 이루어져야 할 때
  • 인벤토리 교환: 두 유저 간 아이템 교환 시 양쪽 모두 반영되어야 할 때
핵심 포인트

트랜잭션을 사용하면 중간에 오류가 발생해도 데이터 정합성이 보장됩니다. 예를 들어, 골드를 차감한 후 아이템 지급에 실패하면 골드 차감도 자동으로 취소됩니다.

기본 사용법​

Transaction() 메서드로 트랜잭션 빌더를 생성하고, 작업을 추가한 후 Commit()로 실행합니다.

var result = await DBClient.Transaction()
.From<User>().Where(x => x.Id == visitorId).Update(updatedUser)
.From<Inventory>().Insert(newItem)
.Commit();

if (result.Success)
{
Debug.Log($"트랜잭션 성공: {result.OperationCount}개 작업 완료");
}
else
{
Debug.LogError($"트랜잭션 실패: {result.Error}");
}

지원 작업​

작업설명
Insert(model)새 데이터 삽입
Update(model)기존 데이터 수정
Delete()조건에 맞는 데이터 삭제
Inc(field, value)숫자 필드 증가
Dec(field, value)숫자 필드 감소

사용 예제​

재화 거래 (골드로 아이템 구매)​

유저의 골드를 차감하고 인벤토리에 아이템을 추가하는 작업을 원자적으로 처리합니다.

public async Task<bool> PurchaseItem(string visitorId, string itemCode, long price)
{
var newItem = new InventoryItem
{
ItemCode = itemCode,
Quantity = 1,
AcquiredAt = DateTime.UtcNow
};

var result = await DBClient.Transaction()
// 1. 골드 차감
.From<UserCurrency>()
.Where(x => x.UserId == visitorId)
.Dec(x => x.Gold, price)
// 2. 아이템 지급
.From<InventoryItem>()
.Insert(newItem)
.Commit();

return result.Success;
}

아이템 교환​

두 유저 간 아이템을 안전하게 교환합니다.

public async Task<bool> TradeItems(long myItemId, string myUserId, long theirItemId, string theirUserId, string myItemCode, string theirItemCode)
{
var result = await DBClient.Transaction()
// 1. 내 아이템 삭제
.From<InventoryItem>()
.Where(x => x.Id == myItemId)
.Delete()
// 2. 상대 아이템 삭제
.From<InventoryItem>()
.Where(x => x.Id == theirItemId)
.Delete()
// 3. 상대 아이템을 내게 지급
.From<InventoryItem>()
.Insert(new InventoryItem
{
ItemCode = theirItemCode,
Quantity = 1,
AcquiredAt = DateTime.UtcNow
})
// 4. 내 아이템을 상대에게 지급
.From<InventoryItem>()
.Insert(new InventoryItem
{
ItemCode = myItemCode,
Quantity = 1,
AcquiredAt = DateTime.UtcNow
})
.Commit();

return result.Success;
}

TransactionResult​

Commit()는 TransactionResult 객체를 반환합니다.

속성타입설명
Successbool트랜잭션 성공 여부
OperationCountint트랜잭션에 포함된 작업 수
TotalAffectedRowsint영향받은 총 행 수
Messagestring결과 메시지
Errorstring에러 메시지 (실패 시)
var result = await DBClient.Transaction()
.From<User>().Where(x => x.Id == 1).Update(user)
.From<Inventory>().Insert(item)
.Commit();

if (result.Success)
{
Debug.Log($"성공! {result.OperationCount}개 작업, {result.TotalAffectedRows}행 변경");
}
else
{
Debug.LogError($"실패: {result.Error}");
// 모든 작업이 자동으로 롤백됨
}

OfCurrentUser()​

UserTable에서 현재 로그인한 유저의 데이터만 대상으로 작업할 때 사용합니다.

var result = await DBClient.Transaction()
.From<UserCurrency>()
.OfCurrentUser()
.Dec(x => x.Gold, 1000)
.From<InventoryItem>()
.Insert(newItem)
.Commit();

제한사항​

트랜잭션 제한
  • 최대 작업 수: 트랜잭션당 최대 10개 작업까지 지원됩니다.
  • 지원 작업: INSERT, UPDATE, DELETE만 지원됩니다. SELECT는 트랜잭션에 포함할 수 없습니다.
  • WHERE 조건:
    • Delete(): 반드시 Where() 조건이 필요합니다.
    • Update(): Where()가 없으면 모델의 PrimaryKey로 자동 생성됩니다.
    • Inc(), Dec(): 반드시 Where() 조건이 필요합니다.
  • 동일 필드 중복 수정 불가: 같은 작업 내에서 동일한 필드를 여러 번 수정할 수 없습니다.
// 잘못된 예: 동일 필드 중복 수정
await DBClient.Transaction()
.From<User>()
.Where(x => x.Id == visitorId)
.Inc(x => x.Gold, 100)
.Inc(x => x.Gold, 50) // 오류 발생
.Commit();

// 올바른 예: 한 번에 합산하여 수정
await DBClient.Transaction()
.From<User>()
.Where(x => x.Id == visitorId)
.Inc(x => x.Gold, 150) // 100 + 50
.Commit();