스프링 DB 1편(데이터 접근 핵심 원리)

Ch03. 트랜잭션 이해 - 트랜잭션(DB 트랜잭션 실습)

webmaster 2022. 4. 25. 12:54
728x90

H2 데이터 베이스 웹 콘솔 창을 2개 열어두자

  • H2 데이터베이스 웹 콘솔 창을 2개 열 때 기존 URL을 복사하면 안 된다. 꼭 http://localhost:8082를 직접 입력해서 완전히 새로운 세션에서 연결하도록 하자. URL을 복사하면 같은 세션( jsessionId )에서 실행되어서 원하는 결과가 나오지 않을 수 있다

초기 상태

초기 상태 - 데이터 1개만 들어있다(세션1 정보 == 세션2 정보)

//데이터 초기화
set autocommit true;
delete from member;
insert into member(member_id, money) values ('oldId',10000);
  • 자동 커밋 모드로 별도의 Commit 호출이 필요 없다.

신규 데이터 추가 - Commit 이전

세션1 에서 데이터 보이고 세션2에서 데이터 보이지 않는다.

//트랜잭션 시작
set autocommit false; //수동 커밋 모드
insert into member(member_id, money) values ('newId1',10000);
insert into member(member_id, money) values ('newId2',10000);
  • 데이터를 넣은 세션 1에서는 값이 보이지만 데이터를 넣지 않은 세션2 입장에서는 커밋되지 않은 데이터이기에 데이터가 보이지 않는다.

신규 데이터 추가 - Commit 

세션1 에서 데이터 보이고 세션2 에서도 보인다.

commit; //데이터베이스에 반영
  • Commit을 통해 반영하게 되면 모든 세션에서 반영된 결과를 확인할 수 있다.

신규 데이터 추가 - Rollback

Rollback

rollback; //롤백으로 데이터베이스에 변경 사항을 반영하지 않는다.
  • 롤백으로 데이터가 DB에 반영되지 않은 것을 확인할 수 있다.

계좌이체 예제

초기 상태

초기 상태 - 데이터 2개 들어있다(세션1 정보 == 세션2 정보)

set autocommit true;
delete from member;
insert into member(member_id, money) values ('memberA',10000);
insert into member(member_id, money) values ('memberB',10000);
  • memberA 10000원
  • memberB 10000원
  • 자동 커밋 모드로 별도의 Commit 호출이 필요 없다.

계좌이체 실행( Commit 이전)

세션1 에서 데이터가 변경되었고 세션2에서는 데이터가 변경되지 않았다(CommitX)

set autocommit false;
update member set money=10000 - 2000 where member_id = 'memberA';
update member set money=10000 + 2000 where member_id = 'memberB';
  • memberA 의 돈을 memberB에게 2000원 계좌 이체하는 트랜잭션을 실행해보자.
  • 다음과 같은 2번의 update 쿼리가 수행되어야 한다.
  • set autocommit false 로 설정한다. 아직 커밋하지 않았으므로 다른 세션에는 기존 데이터가 조회된다.

계좌이체 - Commit 

commit; //데이터베이스에 반영
  • commit 명령어를 실행하면 데이터베이스에 결과가 반영된다. 다른 세션에서도 memberA의 금액이 8000원으로 줄어들고, memberB의 금액이 12000원으로 증가한 것을 확인할 수 있다.

계좌이체 - Commit 문제 발생

계좌이체 도중 2번째 쿼리 실행 X

set autocommit false;
update member set money=10000 - 2000 where member_id = 'memberA'; //성공
update member set money=10000 + 2000 where member_iddd = 'memberB'; //쿼리 예외발생
  • 계좌이체를 실행하는 도중에 SQL에 문제가 발생한다. 그래서 memberA 의 돈을 2000원 줄이는 것에는 성공했지만, memberB의 돈을 2000원 증가시키는 것에 실패한다.
  • 두 번째 SQL은 member_iddd 라는 필드에 오타가 있다. 두 번째 update 쿼리를 실행하면 SQL 오류가 발생하는 것을 확인할 수 있다.
  • 여기서 문제는 memberA 의 돈은 2000원 줄어들었지만, memberB의 돈은 2000원 증가하지 않았다는 점이다. 결과적으로 계좌이체는 실패하고 memberA의 돈만 2000원 줄어든 상황이다.

강제 커밋

commit
  • 강제 커밋을 하게 된다면 잘못된 결과가 데이터베이스에 그대로 적용된다.
  • 데이터 적합성이 위배되는 큰 문제를 야기한다.

계좌이체 - Rollback

2번째 쿼리를 동작시키는 중에 오류가 발생

set autocommit false;
update member set money=10000 - 2000 where member_id = 'memberA'; //성공
update member set money=10000 + 2000 where member_iddd = 'memberB'; //쿼리 예외발생

Rollback

rollback;
  • 롤백을 호출해서 트랜잭션을 시작하기 전 단계로 데이터를 복구해야 한다.
  • 롤백을 사용한 덕분에 계좌이체를 실행하기 전 상태로 돌아왔다. memberA 의 돈도 이전 상태인 10000 원으로 돌아오고, memberB의 돈도 10000 원으로 유지되는 것을 확인할 수 있다.

정리

  • 원자성: 트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공 하거나 모두 실패해야 한다.
    • 트랜잭션의 원자성 덕분에 여러 SQL 명령어를 마치 하나의 작업인 것 처럼 처리할 수 있었다. 성공하면 한 번에 반영하고, 중간에 실패해도 마치 하나의 작업을 되돌리는 것처럼 간단히 되돌릴 수 있다.
  • 오토 커밋 : 만약 오토 커밋 모드로 동작하는데, 계좌이체 중간에 실패하면 어떻게 될까? 쿼리를 하나 실행할 때 마다 바로바로 커밋이 되어버리기 때문에 memberA의 돈만 2000원 줄어드는 심각한 문제가 발생한다.
  • 트랜잭션 시작 : 따라서 이런 종류의 작업은 꼭 수동 커밋 모드를 사용해서 수동으로 커밋, 롤백 할 수 있도록 해야 한다. 보통 이렇게 자동 커밋 모드에서 수동 커밋 모드로 전환하는 것을 트랜잭션을 시작한다고 표현한다.
728x90