트랜잭션 가이드라인
애플리케이션 코드에서 데이터베이스 트랜잭션을 올바르게 사용하는 방법과 주의사항을 설명합니다.
이 문서는 애플리케이션 코드에서 데이터베이스 트랜잭션을 사용하는 몇 가지 예시를 제공합니다. 추가 참고 자료로 PostgreSQL 문서의 트랜잭션 항목을 확인하세요. 데이터베이스 분해 및 샤딩 # Tenant Scale 그룹 은 GitLab 주 데이터베이스를 분리하고 일부 데이터베이스 테이블을 다른 데이터베이스 서버로 이동할 계획입니다. 먼저 ci_* 관련 데이터베이스 테이블부터 분해를 시작합니다. 현재의 애플리케이션 개발 경험을 유지하기 위해 코드베이스에 툴링과 정적 분석기를 추가하여 올바른 데이터 접근 및 데이터 수정 방법을 보장합니다. 데이터베이스 트랜잭션을 정의하는 올바른 형식을 사용함으로써, 향후 상당한 리팩토링 작업을 줄일 수 있습니다. 트랜잭션 블록 # ActiveRecord 라이브러리는 데이터베이스 구문을 트랜잭션으로 묶는 편리한 방법을 제공합니다: issue = Issue.find(10) project = issue.project ApplicationRecord.transaction do issue.update!(title: 'updated title') project.update!(last_update_at: Time.now) end 이 트랜잭션은 두 개의 데이터베이스 테이블을 포함합니다. 오류가 발생하면 각 UPDATE 구문은 이전의 일관된 상태로 롤백됩니다. ActiveRecord::Base 클래스 참조를 피하고 대신 ApplicationRecord 를 사용하세요. 트랜잭션과 데이터베이스 잠금 # 트랜잭션 블록이 열리면 데이터베이스는 리소스에 필요한 잠금을 획득하려 시도합니다. 잠금의 유형은 실제 데이터베이스 구문에 따라 달라집니다. 다음 코드가 두 개의 서로 다른 프로세스에서 동시에 실행되는 동시 업데이트 시나리오를 고려해 보세요: issue = Issue.find(10) project = issue.project ApplicationRecord.transaction do issue.update!(title: 'updated title') project.update!(last_update_at: Time.now) end 데이터베이스는 참조된 issue 와 project 레코드에 대해 FOR UPDATE 잠금을 획득하려 시도합니다. 이 경우, 두 개의 경쟁 트랜잭션이 이 잠금을 다투며 그 중 하나만 성공적으로 잠금을 획득합니다. 다른 트랜잭션은 첫 번째 트랜잭션이 완료될 때까지 잠금 대기열에서 기다려야 합니다. 두 번째 트랜잭션의 실행은 이 시점에서 차단됩니다. 트랜잭션 속도 # 잠금 경합을 방지하고 안정적인 애플리케이션 성능을 유지하려면 트랜잭션 블록이 가능한 한 빨리 완료되어야 합니다. 트랜잭션이 잠금을 획득하면 트랜잭션이 완료될 때까지 잠금을 유지합니다. 애플리케이션 성능 외에도, 장시간 실행되는 트랜잭션은 데이터베이스 마이그레이션을 차단하여 애플리케이션 업그레이드 프로세스에도 영향을 미칠 수 있습니다. 위험한 예시: 서드파티 API 호출 # 다음 예시를 고려해 보세요: member = Member.find(5