Programing

MySQL : 트랜잭션 대 잠금 테이블

crosscheck 2020. 8. 18. 07:11
반응형

MySQL : 트랜잭션 대 잠금 테이블


데이터베이스 무결성을 보장하고 SELECT 및 UPDATE가 동기화 상태를 유지하고 다른 연결이 간섭하지 않도록하기 위해 트랜잭션 대 잠금 테이블과 약간 혼동됩니다. 다음을 수행해야합니다.

SELECT * FROM table WHERE (...) LIMIT 1

if (condition passes) {
   // Update row I got from the select 
   UPDATE table SET column = "value" WHERE (...)

   ... other logic (including INSERT some data) ...
}

다른 쿼리가 방해하고 동일한 작업을 수행하지 않도록해야합니다 SELECT(연결이 행 업데이트를 완료하기 전에 '이전 값'읽기).

LOCK TABLES table한 번에 하나의 연결 만이 작업을 수행하도록 기본으로 설정 하고 완료되면 잠금을 해제 할 수 있다는 것을 알고 있습니다 . 트랜잭션에서 랩핑하면 동일한 작업을 수행 할 수 있습니까 (다른 연결이 여전히 처리중인 동안 다른 연결이 동일한 프로세스를 시도하지 않도록 보장)? 아니면 것 SELECT ... FOR UPDATE또는 SELECT ... LOCK IN SHARE MODE더 나은?


테이블을 잠그면 다른 DB 사용자가 잠근 행 / 테이블에 영향을주지 않습니다. 그러나 잠금 자체는 논리가 일관된 상태로 나오는 것을 보장하지 않습니다.

은행 시스템을 생각해보십시오. 온라인으로 청구서를 지불 할 때 거래의 영향을받는 두 개 이상의 계정이 있습니다. 즉, 돈을 인출하는 계정입니다. 그리고 돈이 이체되는 수신자의 계정. 그리고 거래에 부과 된 모든 서비스 수수료를 기꺼이 입금 할 은행 계좌. (요즘 모두가 알고 있듯이) 은행이 엄청나게 어리 석다는 것을 감안할 때, 그들의 시스템이 다음과 같이 작동한다고 가정 해 봅시다.

$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
    charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;

$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance

이제 잠금 및 거래가없는이 시스템은 다양한 경쟁 조건에 취약하며, 그중 가장 큰 것은 귀하의 계정 또는 수신자의 계정에서 동시에 수행되는 여러 결제입니다. 코드에서 잔액을 검색하고 huge_overdraft_fees () 등을 수행하는 동안 다른 결제가 동일한 유형의 코드를 병렬로 실행할 가능성이 전적으로 가능합니다. 그들은 당신의 잔액 (예 : $ 100)을 회수하고, 그들의 거래를 할 것입니다 (당신이 지불하는 $ 20와 그들이 당신을 망쳐 놓은 $ 30을 꺼냄), 이제 두 코드 경로에 두 가지 다른 잔액이 있습니다 : $ 80와 70 달러. 마지막으로 완료되는 항목에 따라 계정에있는 두 잔고 중 하나가됩니다 ($ 100-$ 20-$ 30). 이 경우 "귀하의 은행 오류"

이제 자물쇠를 사용한다고 가정 해 보겠습니다. 청구서 지불 ($ 20)이 먼저 파이프에 도달하므로 계정 기록을 확보하고 잠급니다. 이제 독점 사용이 가능하며 잔액에서 20 달러를 공제하고 새 잔액을 안심하고 다시 쓸 수 있습니다. 그러면 계정이 예상대로 80 달러가됩니다. 하지만 ... 어 ... 당신은 수취인의 계좌를 업데이트하려고하는데, 그것은 잠겨 있고 코드가 허용하는 것보다 더 오래 잠겼습니다. 당신의 거래 시간이 초과되었습니다 ... 우리는 어리석은 은행들을 다루고 있습니다. 그래서 적절한 오류 대신에 처리, 코드는 단지을 당기고 exit()$ 20는 전자의 퍼프로 사라집니다. 이제 당신은 20 달러를 내고 여전히 수신자에게 20 달러를 빚지고 있으며 전화기는 회수됩니다.

그래서 ... 거래를 입력하세요. 당신은 거래를 시작하고, 당신의 계좌에서 $ 20를 인출하고, 당신은 수신자에게 $ 20을 입금하려고합니다. 그리고 뭔가가 다시 터집니다. 그러나 이번에 exit()는 코드 대신을 할 수 rollback있으며 휙 휙, $ 20가 마법처럼 계정에 다시 추가됩니다.

결국 다음과 같이 요약됩니다.

잠금은 다른 사람이 처리중인 데이터베이스 레코드를 방해하지 못하도록합니다. 트랜잭션은 "이후"오류가 "이전"작업을 방해하지 않도록합니다. 둘 중 어느 쪽도 결국 모든 것이 정상적으로 작동한다고 보장 할 수 없습니다. 하지만 함께라면 그렇습니다.

내일 수업 : 교착 상태의 기쁨.


일반적으로 SELECT는 트랜잭션에 있는지 여부에 관계없이 테이블을 잠그지 않기 때문에 트랜잭션 내부 SELECT ... FOR UPDATE또는 SELECT ... LOCK IN SHARE MODE트랜잭션을 원합니다 . 선택하는 것은 트랜잭션이 진행되는 동안 다른 트랜잭션이 해당 행을 읽을 수 있는지 여부에 따라 다릅니다.

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

START TRANSACTION WITH CONSISTENT SNAPSHOT다른 트랜잭션이 계속해서 해당 행을 수정할 수 있으므로 트릭을 수행하지 않습니다. 이것은 아래 링크의 맨 위에 언급되어 있습니다.

다른 세션이 동시에 같은 테이블을 업데이트하면 [...] 데이터베이스에 존재하지 않는 상태의 테이블을 볼 수 있습니다.

http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html


I had a similar problem when attempting a IF NOT EXISTS ... and then performing an INSERT which caused a race condition when multiple threads were updating the same table.

I found the solution to the problem here: How to write INSERT IF NOT EXISTS queries in standard SQL

I realise this does not directly answer your question but the same principle of performing an check and insert as a single statement is very useful; you should be able to modify it to perform your update.


Transaction concepts and locks are different. However, transaction used locks to help it to follow the ACID principles. If you want to the table to prevent others to read/write at the same time point while you are read/write, you need a lock to do this. If you want to make sure the data integrity and consistence, you had better use transactions. I think mixed concepts of isolation levels in transactions with locks. Please search isolation levels of transactions, SERIALIZE should be the level you want.


You are confused with lock & transaction. They are two different things in RMDB. Lock prevents concurrent operations while transaction focuses on data isolation. Check out this great article for the clarification and some graceful solution.


I'd use a

START TRANSACTION WITH CONSISTENT SNAPSHOT;

to begin with, and a

COMMIT;

to end with.

Anything you do in between is isolated from the others users of your database if your storage engine supports transactions (which is InnoDB).

참고URL : https://stackoverflow.com/questions/4226766/mysql-transactions-vs-locking-tables

반응형