4

closure_tree을 사용하여 계층 구조에서 공통 속성을 가진 모델 세트를 동시에 조작 할 때 데이터베이스 교착 상태를 피하는 방법은 무엇입니까?클로저 트리 계층을 동시에 편집 할 때 교착 상태

그들은 다음과 같은 맛을 제공 :

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    DELETE FROM `element_hierarchies` 
    WHERE descendant_id IN (
    SELECT DISTINCT descendant_id 
    FROM (SELECT descendant_id 
     FROM `element_hierarchies` 
     WHERE ancestor_id = 16332 
    ) AS x) 
    OR descendant_id = 16332 

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    INSERT INTO `element_hierarchies` (`ancestor_id`, `descendant_id`, `generations`) VALUES (30910, 30910, 0) 

with_advisory_lock 유망 보이는 폐쇄 테이블을 다시 작성하는 경우

것은 #append/prepend_sibling

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    UPDATE `elements` SET `sort_order` = `sort_order` + 1 WHERE (`parent_id` = 28035 AND `sort_order` >= 1) 

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    UPDATE `elements` SET `sort_order` = `sort_order` - 1 WHERE (`parent_id` = 21168 AND `sort_order` <= -1) 

을 발행합니다. 이견있는 사람?

답변

3

저자 :

씨 치유의 조언은 일반적으로 올바른-당신은 교착 상태를 방지하기 위해 같은 순서로 테이블 잠금을 획득해야한다. 그러나이 경우 교착 상태는 행 수준의 계층 구조 테이블 잠금 때문입니다.

재미있는 점은 with_advisory_lock을 사용하는 것이 좋습니다! 방금 closure_tree에 해당 라이브러리를 썼습니다. 버전이 3.7.0 이상인 경우 이미 클래스 수준 #rebuild#find_or_create_by_path 메서드를 보호하는 자문 잠금이 있습니다.

자물쇠 (적어도 MySQL과 PostgreSQL의 경우)의 문제점은 트랜잭션 경계를 존중하지 않는다는 것입니다. 잠금을 해제 한 호출자가 잠금을 해제하기 전에 트랜잭션을 커밋하지 않으면 다른 연결이 표시되지 않습니다 자문 잠금을 획득하려고 할 때 이러한 변경 사항이 있으므로 여기에서주의해야합니다. 쓰기를 위해 계층 테이블에 테이블 잠금을 추가해야 할 수도 있지만 최악의 경우가 될 수 있습니다.

나는 issue 41을 열 었으며 그곳에서 추적 할 수 있습니다. 우선 할 일은 병렬 테스트에서 교착 상태를 안정적으로 재현하는 것입니다. 우리는 이미 #rebuild#find_or_create_by_path에 대한 테스트를 수행했습니다.

+1

이 문제는 해결되었습니다. v3.7.3으로 업그레이드하십시오. – mrm

+0

http://stackoverflow.com/questions/41388300/use-ruby-closure-tree-gem-without-rails에서 내 질문을 살펴볼 수 있습니까? – peter

2

하나의 트랜잭션을 다른 트랜잭션과 함께 사용하는 방법을 고려해야합니다. 가장 좋은 방법은 읽은 물건을 먼저 (선택)하고 나중에 SQL을 쓰는 것입니다. 또한 쓰기 SQL이 동일한 순서로 테이블을 사용하는지 확인하십시오. 즉, 두 경우 모두 테이블 A와 B에 쓰십시오. 이렇게하면 다른 트랜잭션에 의해 잠금을 요구하는 다른 트랜잭션이 보유하고있는 동안 잠금이 필요하지 않게됩니다.

또는 교착 상태를 감지하고 적절한 조치를 취할 수 있습니다. 나는 그들을 처음부터 피하는 것이 좋습니다. 여기 closure_tree