문서 메뉴
문서 홈
/ / /
Ruby MongoDB Driver
/

트랜잭션

이 페이지의 내용

  • 트랜잭션 사용
  • 로우 레벨 API
  • 커밋 재시도
  • 트랜잭션 중첩

버전 4. MongoDB 서버의 0 는 다중 문서 트랜잭션을 도입합니다. (단일 문서 내의 여러 필드에 대한 업데이트는 모든 버전의 MongoDB에서 원자적으로 이루어집니다.) Ruby 드라이버 버전 2.6.0 트랜잭션에 대한 지원을 추가합니다.

트랜잭션을 시작하려면 애플리케이션에 세션이 있어야 합니다.

트랜잭션을 사용하는 데 권장되는 방법은 with_transaction 헬퍼 메서드를 사용하는 것입니다.

session = client.start_session
session.with_transaction do
collection.insert_one({hello: 'world'}, session: session)
end

with_transaction 헬퍼는 다음을 수행합니다.

  • 제공된 블록을 호출하기 전에 트랜잭션을 시작하고, 블록이 완료되면 트랜잭션을 커밋합니다.

  • 차단에 포함된 작업이나 커밋 작업으로 인해 일시적인 트랜잭션 오류가 발생하면 차단 및/또는 커밋이 다시 실행됩니다.

블록은 여러 번 호출될 수 있으므로 멱등성이어야 합니다.

차단은 commit_transaction 또는 abort_transaction 을(를) 호출하여 트랜잭션을 명시적으로 커밋하거나 중단할 수 있습니다. 이 경우 with_transaction 은 커밋이나 중단을 시도하지 않습니다(그러나 차단 밖으로 전파된 일시적인 트랜잭션 오류가 발생하면 차단을 다시 시도할 수 있습니다).

트랜잭션의 커밋 결과를 알 수 없는 경우에도 차단이 다시 시도됩니다. 예를 들어, 커밋 중에 cluster가 투표를 거치는 경우 이런 일이 발생할 수 있습니다. 이 경우 차단을 다시 시도하면 토폴로지의 주 서버가 변경되었을 수 있습니다.

현재 with_transaction 는 실행 시작 후 120초가 지나면 차단 재시도를 중지하고 커밋합니다. 이 시간은 구성할 수 없으며 향후 드라이버 버전에서 변경될 수 있습니다. 그렇다고 해서 with_transactions 의 전체 런타임이 120초 이하로 보장되는 것은 아니며, 벽시계 시간이 120초가 지나면 더 이상의 재시도가 시작되지 않습니다.

트랜잭션에 대한 더 많은 제어가 필요한 경우 낮은 수준의 API도 사용할 수 있습니다.

with_transactionstart_transaction 와 동일한 읽기 고려 (read concern), 쓰기 고려 (write concern), 읽기 설정 (read preference) 옵션을 사용합니다.

session = client.start_session
session.with_transaction(
read_concern: {level: :majority},
write_concern: {w: 3},
read: {mode: :primary}
) do
collection.insert_one({hello: 'world'}, session: session)
end

with_transaction 블록 내부의 명령이 실패하면 서버의 트랜잭션이 중단될 수 있습니다. 이 상황은 일반적으로 드라이버에 의해 투명하게 처리됩니다. 그러나 애플리케이션이 이러한 오류를 포착하고 다시 발생시키지 않으면 드라이버는 트랜잭션이 중단되었는지 여부를 확인할 수 없습니다. 그러면 드라이버는 차단을 무기한 다시 시도합니다.

이러한 상황을 방지하려면 애플리케이션이 with_transaction 블록 내의 오류를 조용히 처리하지 않아야 합니다. 애플리케이션이 차단 내의 오류를 처리해야 하는 경우 오류를 다시 발생시켜야 합니다.

session.with_transaction do
collection.insert_one({hello: 'world'}, session: session)
rescue Mongo::Error::OperationFailure => e
# Do something in response to the error
raise e
end

애플리케이션이 사용자 지정 방식으로 오류를 처리해야 하는 경우 대신 낮은 수준의 API를 사용해야 합니다.

트랜잭션은 세션에서 start_transaction 메서드를 호출하여 시작할 수 있습니다.

session = client.start_session
session.start_transaction

트랜잭션을 시작할 때 읽기 고려 (read concern), 쓰기 고려 (write concern), 읽기 설정 (read preference)을 지정할 수도 있습니다.

session = client.start_session
session.start_transaction(
read_concern: {level: :majority},
write_concern: {w: 3},
read: {mode: :primary})

트랜잭션에서 데이터베이스에 대한 변경 사항을 유지하려면 트랜잭션을 명시적으로 커밋해야 합니다. 세션이 열린 트랜잭션으로 종료 되면 트랜잭션이 중단 됩니다. 트랜잭션을 명시적으로 중단할 수도 있습니다.

트랜잭션을 커밋하거나 중단하려면 세션 인스턴스에서 commit_transaction 또는 abort_transaction 를 호출합니다.

session.commit_transaction
session.abort_transaction

참고: 미해결 트랜잭션은 데이터베이스와 같은 서버의 다양한 객체에 대한 잠금을 보유할 수 있습니다. 예를 들어 다음 스니펫의 삭제 호출은 서버가 만료되고 트랜잭션이 중단될 때까지 transactionLifetimeLimitSeconds 초(기본값 60) 동안 중단됩니다.

c1 = Mongo::Client.new(['127.0.0.1:27017']).use(:test_db)
session = c1.start_session
c1['foo'].insert_one(test: 1)
session.start_transaction
c1['foo'].insert_one({test: 2}, session: session)
c2 = Mongo::Client.new(['127.0.0.1:27017']).use(:test_db)
# hangs
c2.database.drop

트랜잭션은 서버 측 세션과 연결되므로 클라이언트를 닫아도 이 클라이언트가 시작한 트랜잭션이 중단되지는 않습니다. 애플리케이션은 abort_transaction 을(를) 호출하거나 서버 측에서 트랜잭션이 시간 초과될 때까지 기다려야 합니다. 트랜잭션을 커밋하거나 중단하는 것 외에도 애플리케이션은 이 세션에서 트랜잭션이 진행 중인 경우 중단할 세션을 종료할 수도 있습니다.

session.end_session
c2 = Mongo::Client.new(['127.0.0.1:27017']).use(:test_db)
# ok
c2.database.drop

트랜잭션 내부의 명령이 실패하면 서버에서 트랜잭션이 중단될 수 있습니다. 트랜잭션을 중단하는 오류는 오류 레이블에 TransientTransactionError 이(가) 없습니다. 이러한 트랜잭션을 커밋하려는 시도는 NoSuchTransaction 오류와 함께 거부됩니다.

트랜잭션 커밋이 실패하면 다시 시도할 수 있습니다 . 이를 위한 Ruby 코드는 다음과 같습니다.

begin
session.commit_transaction
rescue Mongo::Error => e
if e.label?('UnknownTransactionCommitResult')
retry
else
raise
end
end

MongoDB는 트랜잭션 중첩을 지원하지 않습니다. 트랜잭션이 이미 진행 중인 상태에서 start_transaction 또는 with_transaction 을(를) 호출하려고 하면 오류가 발생합니다.

돌아가기

세션

다음

사용 중 암호화