2014-10-30 4 views
0

저는 여러 번 작업을 처리하는 php 프로그램을 만들고 있습니다. 여러 작업자 프로세스가 자율적으로 작업 테이블을 처리합니다. 각 프로세스는 자신의 mysql 연결을 열어서 (이것은 php의 포크 아키텍처로 인해 필요합니다) 자체 작업 (두 작업자가 동일한 작업을 수행하지 않아야 함)에서 작업해야합니다. 이를 위해 작업자는 작업을 시작하기 전에 작업을 "수행"합니다. 이것은 다음과 같이 이루어진다 :동일한 행을 업데이트하는 여러 프로세스가 mysql에서 교착 상태가 발생합니까?

  1. 노동자는 모두 "대기"작업이 이러한 작업이 반복되는
  2. 조회하는
  3. 트랜잭션이 시작되는 작업을 요청합니다. 그런 다음 스크립트는 상태를 업데이트하여 각 작업을 "수행"하려고합니다. 그 동안 업데이트가 완료되지 않았는지 확인하기 위해 업데이트의 상태는 where status = 'pending'입니다.
  4. 작업이 성공적으로 "수행"되면 즉시 반복이 중지되고 트랜잭션이 커밋됩니다.

mysql 셸에서이 시나리오를 테스트 한 결과, 2 개의 터미널 창에서 데이터베이스에 처음 두 번 연결되었습니다. 둘 다에서 거래를 시작했습니다. 그런 다음 작업을 첫 번째 창에서 "촬영"하도록 업데이트했습니다. 두 번째 창에서 동일한 작업을 업데이트하려고 시도했습니다. 두 번째 창은 첫 번째 창에서 트랜잭션을 커밋하고 정중하게 실패 할 때까지 기다렸습니다 (0 행이 영향을 받음).

이제 PHP로 (PDO)와 함께 즉시 두 번째 프로세스가 작업을하려고, 나는이 DB에 교착 얻을 :

PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction' in ...

난 단지 포장하는 경우는 잘 모르겠어요를 실제 은 트랜잭션을 수행하여으로 작업을 업데이트합니다. 그러나 내 opinon에서, 내가 프로그램에서 그것을하고있는 방식은 쉘에서 수행 한 동일한 별자리이므로 작동해야합니다.

내가 누락 된 부분을 누군가가 도와 줄 수 있습니까?

+0

작업 표의 유형은 'MyISAM'또는 'InnoDB'입니까? 귀하의 경우에는 'InnoDB'가 설정되어야합니다 –

+1

교착 상태는 무서워 할 것이 아니라 정상입니다. 이러한 유형의 문제를 처리하는 일반적인 방법은 트랜잭션을 다시 시작하는 것입니다. 교착 상태로 인해 실패한 횟수를 추적하고 간단하게 시도를 중지 할 수 있습니다. 작업이 완료되지 않고 다른 작업자가 결국 작업을 포착합니다. –

+0

@ N.B .: 기본적으로 mysql이 "트랜잭션을 시작한 이후로 다른 프로세스가이 행을 이미 업데이트했습니다."라고 말하는 것입니다. 트랜잭션을 어떻게 다시 시작합니까? – Chris

답변

0

당신은 InnoDB에 있습니다.

작업이 테이블에 있습니까? 나는 그들이 그렇다고 생각하지만, 당신은 그렇게 명시 적으로 말하지 않았습니다.

작업 할 작업을 잡는 데이 분야를 사용해보십시오.

BEGIN; /* start a transaction */ 
SELECT task_id, whatever 
    FROM tasktable 
WHERE status = 'pending' 
LIMIT 1 
FOR UPDATE; 

그런 다음 작업 ID가있는 행이 반환되면 해당 작업을 처리 할 수 ​​있습니다. 행이 반환되지 않으면 보류중인 작업이 없습니다.

작업을 작동으로 표시하십시오. 당신이 교착 상태 예외 (당신은 여전히 ​​하나를 얻을 수 있습니다, 그러나 희소 예정) 다음 ROLLBACK;를 발급을받을 경우

UPDATE tasktable 
    SET status = 'working' 
WHERE task_id = <<the task ID you just got back>>; 

,

COMMIT; 

은 다시 전체 순서를보십시오.

그런 다음 작업을 수행하십시오. 완료되면 완료로 표시하십시오. 하나의 쿼리로 트랜잭션을 수행 할 수 있기 때문에 트랜잭션이 필요하지 않습니다.

클라이언트 연결에서 자동 커밋을 해제 한 경우 해당 쿼리를 커밋하는 것을 잊지 마십시오.

+0

답장을 보내 주셔서 감사합니다. 이것은 제가하고있는 일과 문제가있는 일입니다. – Chris

0

나는 "solution" that I'm going with을 발견했다. 다른 사람이 다른 해결책을 가지고 있다면, 나는 그것을 듣기 위해 마음을 열고 끝내면 답을 행복하게 받아 들일 것입니다.

기본적으로 루프에서 작업을 "수행"하려고 할 때, 교착 상태가 발생하면 롤백하고 다시 시도하십시오. 첫 번째 테스트는 모든 직원이 작업을 시도 할 때 초기 문제를 해결한다는 것을 보여줍니다.

관련 문제