2011-03-24 2 views
5

필자의 레일 애플리케이션에서 다음과 같은 코드가 있습니다.작업을 위해 일련의 개체를 잠 그려면 어떻게해야합니까?

def foo 
    if object_bar_exists 
    raise "can't create bar twice!" 
    end 

    Bar.create 
end 

두 가지 요청이 응용 프로그램 서버로 들어 오면 호출 될 수 있습니다. 이 코드가 동시에 두 요청에 의해 실행되고 두 코드가 동시에 if 검사를 실행하면 둘 다 다른 bar을 찾지 않고 2 bar가 작성됩니다.

"모음 모음"에 대해 "뮤텍스"를 만드는 가장 좋은 방법은 무엇입니까? DB에있는 특수 목적의 뮤텍스 테이블?

여기서 메모리 상호 배제는 사용할 수 없다는 것을 강조합니다.

답변

4

가장 좋은 방법은 DB 트랜잭션에서 작업을 수행하는 것입니다. 아마도 결국에는 여러 응용 프로그램이 실행되고 메모리를 공유하지 않기 때문에 응용 프로그램 수준에서 뮤텍스 잠금을 만들 수 없습니다. 특히 두 응용 프로그램 서비스가 완전히 다른 물리적 상자에서 실행되는 경우에는 특히 그렇습니다. 요청 저장 무효가 롤백을 일으킬 수 있도록 당신은 DB 트랜잭션의 롤백을 확인하려면

ActiveRecord::Base.transaction do 
    # Transaction code goes here. 
end 

은 다음 검증이 바 클래스를 사용하도록 설정해야합니다 다음은 DB 트랜잭션을 수행하는 방법은 다음과 같습니다 이미 DB에있는 바 객체가있는 경우

ActiveRecord::Base.transaction do 
    bar = Bar.new(params[:bar]) 
    bar.save! 
end 

,이 같은 비관적 객체를 잠글 수 있습니다 :

ActiveRecord::Base.transaction do 
    bar = Bar.find(1, :lock => true) 
    # perform operations on bar 
end 
+1

나는 거래가 그 내부의 모든 것이 원자 적으로 수행되는 것을 보장한다고 생각했다. 동일한 트랜잭션을 사용하는 코드를 병렬로 두 프로세스에서 실행할 수없고 동일한 문제가 있습니까? (최초의'if' 검사가 병렬로 실행되고 성공하면, 그리고 병렬 적으로 쓰기가 일어나며, 두 경우 모두 각각의 코드가 원자 적으로 발생합니다.) –

+0

행을 잠그지 않을 경우. 이것은 DB에서 행 수준 잠금이므로 다른 트랜잭션이 액세스 할 수 없습니다.또한 고유 한 행을 보장하는 유효성 검증 오류가있는 경우 첫 번째 쓰기가 성공하고 다음 번에 실패하여 전체 트랜잭션을 롤백합니다. –

+2

정말로 ** 트랜잭션 ** 및 ** 데이터베이스 내에서 고유 한 인덱스를 사용하여 문제가 발생하게하십시오. 일이 잘못 될 때 트랜잭션은 모든 것을 깨끗하게 유지할 것이고, 일이 잘못 될 때 고유 인덱스가 알려줄 것입니다. –

1

모든 요청이 동일한 머신과 동일한 루비 가상 머신에 들어오는 경우 Ruby의 Mutex 내장 클래스 (Mutex Docs)를 사용할 수 있습니다.

기계 또는 rvms가 여러 개인 경우 db 개체가 db에 저장되었다고 가정하면 Bar 개체를 생성/가져 오기 위해 데이터베이스 트랜잭션을 사용해야합니다.

0

을 나는아마 것객체를 lib 디렉토리에 두어 인스턴스의 인스턴스가 하나만 있고 Mutexes을 사용하여 잠그십시오.

이렇게하면 특정 시점에서 한 가지만 액세스 할 수 있습니다. 물론, 다른 요청도 차단되므로 기억해야 할 사항입니다.

여러 컴퓨터의 경우 데이터베이스에 토큰을 저장하고 토큰에 대한 일종의 액세스를 동기화해야합니다. 마찬가지로, 토큰은 질의되고 꺼내 져야하며 사람들이 토큰을 동시에 제거 할 수 없도록하기 위해 숫자 나 무언가를 추적해야합니다. 또는 토큰 처리가 한 지점에서만 이루어 지도록 중앙 잠금 웹 서비스를 사용하십시오.

관련 문제