Ruby on Rails
액티브 레코드 거래
수색…
비고
트랜잭션은 SQL 문이 모두 하나의 기본 동작으로 성공할 수있는 경우에만 영구적 인 보호 블록입니다. 고전적인 예는 인출이 성공한 경우에만 입금 할 수있는 두 개의 계좌 간의 이체 및 그 반대의 경우입니다. 트랜잭션은 데이터베이스의 무결성을 강화하고 프로그램 오류 또는 데이터베이스 고장으로부터 데이터를 보호합니다. 따라서 기본적으로 트랜잭션 블록을 사용해야합니다. 여러 개의 명령문을 함께 실행해야하거나 전혀 실행하지 않아야합니다.
기본 예제
예 :
ActiveRecord::Base.transaction do
david.withdrawal(100)
mary.deposit(100)
end
이 예는 오직 다윗에게서 돈을 가져다가 인출이나 예금으로 예외를 두지 않으면 마리아에게 준다. 예외는 트랜잭션이 시작되기 전의 상태로 데이터베이스를 리턴하는 ROLLBACK을 강제 실행합니다. 그러나 객체의 인스턴스 데이터는 트랜잭션 전 상태로 반환되지 않습니다.
단일 트랜잭션에서 다른 ActiveRecord 클래스
트랜잭션 클래스 메서드가 일부 ActiveRecord 클래스에서 호출되었지만 트랜잭션 블록 내의 개체가 모두 해당 클래스의 인스턴스 일 필요는 없습니다. 이는 트랜잭션이 모델별로가 아니라 데이터베이스 별 연결이기 때문입니다.
이 예제에서는 계정 클래스에서 트랜잭션이 호출 되더라도 잔액 레코드가 트랜잭션으로 저장됩니다.
Account.transaction do
balance.save!
account.save!
end
트랜잭션 메소드는 모델 인스턴스 메소드로 사용할 수도 있습니다. 예를 들어 다음과 같이 할 수도 있습니다.
balance.transaction do
balance.save!
account.save!
end
다중 데이터베이스 연결
트랜잭션은 단일 데이터베이스 연결에서 작동합니다. 클래스 별 데이터베이스가 여러 개있는 경우 트랜잭션은 트랜잭션을 상호 작용할 수 없습니다. 한 가지 해결 방법은 모델을 변경 한 각 클래스에서 트랜잭션을 시작하는 것입니다.
Student.transaction do
Course.transaction do
course.enroll(student)
student.units += course.units
end
end
이것은 좋지 않은 솔루션이지만 완전히 분산 된 트랜잭션은 ActiveRecord의 범위를 벗어납니다.
저장 및 삭제는 트랜잭션에서 자동으로 래핑됩니다.
#save와 #destroy 모두 트랜잭션에 랩핑되어 검증 또는 콜백에서 수행하는 작업이 보호 대상에서 수행되도록 보장합니다. 따라서 유효성 검사를 사용하여 트랜잭션이 의존하는 값을 확인하거나 after_*
콜백을 포함하여 롤백에 대한 콜백에서 예외를 발생시킬 수 있습니다.
따라서 작업이 완료 될 때까지 데이터베이스 외부의 변경 내용이 표시되지 않습니다. 예를 들어, after_save
에서 검색 엔진 색인을 업데이트하려고하면 인덱서는 업데이트 된 레코드를 보지 않습니다. after_commit
콜백은 업데이트가 커밋 된 후에 트리거됩니다.
콜백
트랜잭션을 커밋하고 롤백하는 것과 관련된 두 가지 유형의 콜백 ( after_commit
및 after_rollback
있습니다.
after_commit
콜백은 트랜잭션이 커밋 된 직후 트랜잭션 내에서 저장되거나 소멸되는 모든 레코드에서 호출됩니다. after_rollback
콜백은 트랜잭션 또는 세이브 포인트가 롤백 된 직후 트랜잭션 내에서 저장되거나 파괴 된 모든 레코드에서 호출됩니다.
이러한 콜백은 데이터베이스가 영구적 인 상태 일 때만 콜백이 실행된다는 것을 보장하므로 다른 시스템과 상호 작용할 때 유용합니다. 예를 들어, after_commit
은 트랜잭션 내에서 캐시를 지우면 데이터베이스가 업데이트되기 전에 캐시가 재생성 될 수 있기 때문에 캐시를 지우는 데 적합합니다.
트랜잭션 롤백
ActiveRecord::Base.transaction
은 ActiveRecord::Rollback
예외를 사용하여 의도하지 않은 롤백을 다른 예외 상황과 구별합니다. 일반적으로 예외를 발생 시키면 .transaction
메서드가 데이터베이스 트랜잭션을 롤백하고 예외를 전달합니다. 그러나 ActiveRecord::Rollback
예외를 발생 시키면 예외를 ActiveRecord::Rollback
않고 데이터베이스 트랜잭션이 롤백됩니다.
예를 들어, 컨트롤러에서 트랜잭션을 롤백 할 수 있습니다.
class BooksController < ActionController::Base
def create
Book.transaction do
book = Book.new(params[:book])
book.save!
if today_is_friday?
# The system must fail on Friday so that our support department
# won't be out of job. We silently rollback this transaction
# without telling the user.
raise ActiveRecord::Rollback, "Call tech support!"
end
end
# ActiveRecord::Rollback is the only exception that won't be passed on
# by ActiveRecord::Base.transaction, so this line will still be reached
# even on Friday.
redirect_to root_url
end
end