2012-05-07 2 views
1

내 애플리케이션에서 교착 상태 문제를 조사하려고합니다. 내 테이블은 이런 식으로 보입니다.MySQL InnoDB에서 다음과 같은 쿼리가 잠길 때

CREATE TABLE `requests` (
    `req_id` bigint(20) NOT NULL auto_increment, 
    `status` varchar(255) default NULL, 
    `process_id` varchar(200) default NULL, 
    PRIMARY KEY (`req_id`), 
    KEY `status_idx` USING BTREE (`status`), 
    KEY `pk_idx_requests` USING BTREE (`req_id`), 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
  • 이 서비스는 (다중 스레드) 문제는이 테이블에 문을 삽입합니다.
  • 여러 클라이언트가 두 개의 별도 트랜잭션에서 다음 쿼리를 순서대로 발행합니다.

    업데이트 요청 설정 PROCESS_ID = ' "+ 여기서 hostName +" "상태 ='완료 '및 PROCESS_ID가 null 순서 req_id 오름차순 한도 100 여기서"요청에서 *

    선택 여기서 PROCESS_ID =' "+ 여기서 hostName +" '어디 상태 ='수신 ';

    업데이트 요청 상태를 설정 ='XYZ '3 쿼리

Req_id 2 쿼리에서 검색 REQ ID의 목록입니다'req_id = '이 처리

,536,913,632. 10

그러나 클라이언트 측에서 어떤 경우에는 예외가 발생합니다.

Deadlock found when trying to get lock; try restarting transaction 
org.hibernate.exception.LockAcquisitionException: could not execute native bulk manipulation query 

위의 쿼리로 인해 교착 상태가 발생할 수 있습니까? 그렇다면 어떻게 해결할 수 있습니까? 또한이 문제를 로컬에서 재현 할 수있는 방법이 있습니까? 여기

는 '쇼 InnoDB의 상태'의 출력이

LATEST DETECTED DEADLOCK 
------------------------ 
120507 6:03:21 
*** (1) TRANSACTION: 
TRANSACTION 115627, ACTIVE 1 sec starting index read 
mysql tables in use 1, locked 1 
LOCK WAIT 3 lock struct(s), heap size 1248, 25 row lock(s) 
MySQL thread id 432399, OS thread handle 0x419e4940, query id 4111695 * * * Searching rows for update 
update requests set process_id='**' where status='Received' and process_id is null order by req_id asc limit 100 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 4 page no 3797 n bits 136 index `PRIMARY` of table `db`.`requests` trx id 115627 lock_mode X locks rec but not gap waiting 
Record lock, heap no 67 PHYSICAL RECORD: n_fields 27; compact format; info bits 0 
*** (2) TRANSACTION: 
TRANSACTION 115626, ACTIVE 1 sec updating or deleting 
mysql tables in use 1, locked 1 
3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1 
MySQL thread id 432403, OS thread handle 0x41c19940, query id 4111694 * * * Updating 
update requests set status='Processing', process_id='**' where req_id=3026296 
*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 4 page no 3797 n bits 136 index `PRIMARY` of table `db`.`requests` trx id 115626 lock_mode X locks rec but not gap 
Record lock, heap no 67 PHYSICAL RECORD: n_fields 27; compact format; info bits 0 
+0

'show engine innodb status'출력이 거의 수정되지 않았습니다. – RandomQuestion

답변

2

MySQL은 UPDATE 문에이 기록을 방문 처음으로 잠금을 쓰기합니다

일부 배경. 잠금을 읽기에서 쓰기로 올리지 않습니다. 그것 locks based on the current index.

UPDATE 문에서 MySQL은 상태 열의 인덱스를 사용하기 때문에 MySQL은 status = 'Received'인 모든 레코드를 잠급니다.

기본 키와 같은 고유 색인을 사용하여 두 개 이상의 고유 레코드를 잠글 때마다 간격 (또는 범위)을 잠그는 것에 유의하십시오.

단일 레코드에 대한 업데이트는 여전히 다음 키 잠금을 사용합니다. 즉, 선택한 레코드와 인덱스의 다음 레코드를 잠급니다.

동일한 색인 (다음 키 포함)에서 두 개의 UPDATES이 충돌하지 않습니다 (항상 같은 순서로 잠김). 그러나 범위 잠금이 보조 인덱스와 관련되어 있으므로 교착 상태에 빠질 수 있습니다.

하는의 당신이 req_ids 1과 2 두 개의 레코드가 있다고 가정 해 봅시다 :

여기 발생하는 시나리오입니다.

첫 번째 트랜잭션은 상태 인덱스에 대해 업데이트되고 레코드 1과 2를 모두 잠글 필요가 있지만 기본 키와 동일한 순서로 보장 할 수는 없으므로 레코드 2를 잠그고 레코드 1을 잠근다. .

는 req_id 지수에 두 번째 트랜잭션 잠금

, 기록 1. 즉시 기록 (1) 잠금을 업데이트 할 필요가 있지만, 그것은 또한 두 개의 트랜잭션이 있습니다 2.

기록에 다음 키 잠금을 수행해야 지금 교착 상태. 트랜잭션 1이 2

를 기록 귀하의 경우 교착 상태를 방지하기 위해이 솔루션

을 잠금이 개 필요 기록 (1) 및 트랜잭션을 잠글 필요가 명시 적으로 LOCK TABLES를 사용하여 전체 테이블을 잠금, 또는 단순히을 다시 시도 할 수 트랜잭션이 실패하면. MySQL은 교착 상태를 감지하고 트랜잭션 중 하나가 롤백됩니다.

MySQL은 help you cope with deadlocks에게 몇 가지 지침을 제공합니다.

기본 키에 이미 해당 열이 포함되어 있으므로 중복 키 pk_idx_requests를 삭제해야합니다.

+0

Thnx Marcus. 여기서 T2는 req_id를 기반으로 한 단일 레코드 (프로세스 ID가 이미 설정 됨) 만 업데이트하며 T1은 process_id가 null 인 다른 범위를 업데이트합니다. 두 업데이트가 전체 테이블을 잠그나요? 또한'RECORD LOCKS space id 4 page no 3797 n bit 136 'db.'requests' trx id 115627 lock_mode X가 rec 대기하지만 gap waiting을 잠그지 않았다면'PRIMARY'라고 설명 할 수 있다면 도움이 될 것입니다. – RandomQuestion

+0

또한 '명시 적으로 전체 테이블 잠금'을 사용하여 '업데이트 대상 선택'을 사용 했습니까? – RandomQuestion

+0

@Jitendra, 죄송합니다. 질문을 처음으로 잘못 읽었으므로 답변이 해당 시나리오에 정확하게 맞지 않습니다. 내 대답이 업데이트되었으므로 더 명확해야합니다. 명시 적으로 테이블을'LOCK TABLES'로 잠글 수 있습니다. –

0

예, 이러한 쿼리가 교착 상태가 발생할 수 있습니다. 사실, MySQL doco에서 언급했듯이, 단일 행을 삽입하거나 삭제하는 트랜잭션의 경우에도 교착 상태가 발생할 수 있습니다. How to Cope with Deadlocks

쿼리/업데이트의 속도를 높이기 위해 process_id를 인덱싱 할 수 있습니다.

관련 문제