2014-06-05 2 views
0

레일 3.2.3을 사용하는 응용 프로그램을 실행하고 tinyTDS를 사용하여 MS SQL Sever 인스턴스 위에 연결합니다. 응용 프로그램은 유니콘을 사용하여 4 개의 프로세스가있는 다중 스레드입니다. 문제는 응용 프로그램이 데이터베이스의 필드를 사용하여 각 요청에 고유 계정 번호를 할당하기 위해 증가해야하는 번호를 저장한다는 것입니다. 응용 프로그램을 로컬에서 실행할 때 멀티 스레드가 아니기 때문에 문제가 없습니다.DB에서 증분 값을 저장하는 동안 MS SQL에서 레일스 동시성 문제가 발생했습니다

유니콘을 사용하여 준비 환경에서 실행 중이며 응용 프로그램에 여러 개의 동시 요청이 발생할 때마다 10 명 중 1 명이 중복 카드 번호와 함께 다시 나타납니다. 나는 다음을 시도했다.

레거시 코드

row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table" 
next_card_number = row.value 
row.value = (next_card_number.to_i + 1).to_s 
row.save! 
return next_card_number 

레거시 코드 + 거래

CardValue.transaction do 
    row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table" 
    next_card_number = row.value 
    row.value = (next_card_number.to_i + 1).to_s 
    row.save! 
    return next_card_number 
end 

결과 : 효과 없음

레거시 코드 + with_lock

CardValue.with_lock do 
    row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table" 
    next_card_number = row.value 
    row.value = (next_card_number.to_i + 1).to_s 
    row.save! 
    return next_card_number 
end 

결과 : with_lock이

레거시 코드 + with_lock

CardValue.transaction do 
    lock! 
    row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table" 
    next_card_number = row.value 
    row.value = (next_card_number.to_i + 1).to_s 
    row.save! 
    return next_card_number 
end 

결과 정의되지 않은 것을 오류 : 잠금 오류

답변

0

Transaction is not what you are looking for if your issue is concurrency 정의되지 않습니다. 트랜잭션은 특정 데이터베이스 명령의 올바른 순서와 오류가 발생할 경우 롤백 할 수있는 가능성을 보장하기 위해 작성됩니다. 이것은 당신이 찾고있는 것이 아닙니다.

.with_lock을 인스턴스에서 호출해야합니다. 따라서 CardValue.with_lock이 아니라 my_found_card.with_lock이 아닙니다.

또한. 왜 레일에서 unique id을 만들었습니까? Mysql/mariadb는 자동 증가 기본 키를 사용하여 쉽게 처리 할 수 ​​있습니다.

+0

레일을 생성하는 것은 레거시 시스템에서 비즈니스 요구 사항입니다. 레거시 시스템이 다른 시스템에 연결되어 있기 때문입니다. 내가 바꿀 수있는 것이 아닙니다. – ericglasser

0

레일 문서에 따르면 with_lock이 클래스가 아닌 인스턴스에 적용됩니다. 이것은 레거시 코드 + with_lock 예제의 대체 구현입니다.

row = CardValue.find_by_name("next_card_number") or raise "Missing next_card_number row in card_values table" 
row.with_lock do 
    next_card_number = row.value 
    row.value = (next_card_number.to_i + 1).to_s 
    row.save! 
    return next_card_number 
end