세션A 에서 트랜잭션을 시작하고 데이터를 수정 후 commit 을 하지 않았는데 세션B 에서 동시에 같은 데이터를 수정하게 되면 여러 문제가 발생한다. 바로 트랜잭션의 원자성이 깨지는 것이다.세션A 가 중간에 rollback 을 하게 되면 세션B 는 잘못된 데이터를 수정하는 문제가 발생한다.
이런 문제를 방지하기 위해서 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안에 commit rollback 수행 전까지 다른 세션에서 해당 데이터를 수정할 수 없게 막아야 한다.
그래서 데이터베이스에는 락 이라는 개념이 등장한다.
만약 세션A는 memberA의 금액을 500원으로 변경하고 싶고, 세션B는 memberA의 금액을 1000원으로 변경하려고 한다.
// 세션A
set autocommit false;
update member set money=500 where member_id = 'memberA'
먼저 세션A가 memberA의 금액을 500원으로 수정하고 commit을 수행하지 않았다. memberA 로우의 락은 세션A가 획득한 상태다.
// 세션B
// LOCK_TIMEOUT을 설정하지 않으면 데이터베이스 기본 설정을 따른다
SET LOCK_TIMEOUT 60000;
set autocommit false;
update member set money=1000 where member_id = 'memberA';

이후 세션B에서 memberA의 금액을 1000원으로 수정하려 할 때 세션A가 memberA에 대한 락을 소유중이므로 락이 돌아올 때 까지 대기하게 된다.
// 세션A
commit

세션A에서 commit을 수행하게 되면 세션B에서 락을 획득하며 이전에 실행한 update 쿼리가 반영된다.
// 세션B
commit
세션B에서 commit을 수행하고 나면 모든 작업이 끝나 memberA에 대한 락이 반납 된다.
만약 락을 얻기 위해 대기하다가 지정한 LOCK_TIMEOUT이 경과하면 오류가 발생하게 된다.

보통 데이터를 조회할 때는 락을 획득하지 않고 데이터를 조회할 수 있다. 세션A가 락을 획득하여 데이터를 수정하고 있어도, 세션B에서는 조회가 가능하다.
만약 트랜잭션 종료 시점까지 해당 데이터를 다른 곳에서 변경하지 못하도록 강제로 막아야 할 때 select for update 구문을 사용하면 조회할 때도 락을 획득할 수 있다.

세션A가 select for update 구문을 사용하여 memberA의 데이터 조회와 락을 획득하였다.
세션B는 memberA의 데이터를 수정하려고 하지만 세션A가 락을 획득하여 락을 대기하고 있다.

이후 세션A에서 commit을 수행하면서 락이 반납되고, 세션B가 락을 대기하다가 획득하면서 memberA의 데이터 수정이 반영된다.
최종적으로 세션B가 commit을 수행하면 수정된 내용이 반영된다.