5.1트랜잭션
트랜잭션은 작업의 완전성을 보장해줍니다. 즉 논리적인 작업셋을 모두 완벽하게 처리하거나, 모두 처리하지 못할 경우에는 원 상태로 복구하여 작업의 일부만 적용되는 현상(Partial update)이 발생하지 않게 만들어주는 기능입니다.
트랜잭션은 커밋되거나 롤벡됩니다.
5.1.1 MySql 에서의 트랜잭션
트랜잭션은 하나의 논리적인 작업 셋에 하나의 쿼리가 있든 두개이상의 쿼리가 있든 관계없이 논리적입 작업 셋 자체가 100% 적용되거나(commit을 실행했을때) 아무것도 적용되지않아야 (ROLLBACK) 함을 보장해주는 것입니다.
InnoDB 스토리지엔진 (트랜잭션 지원) vs MyISAM (트랜잭션 미지원)
- 트랜잭션 관점에서 InnoDB 테이블과 MyISAM 테이블이 차이를 살펴보자
-
mysql> CREATE TABLE tab_myisam (fdpk INT NOT NULL, PRIMARY KEY (fdpk) ) ENGINE=MyISAM; mysql> INSERT INTO tab_myisam (fdpk) VALUES (3); mysql> CREATE TABLE tab_innodb (fdpk INT NOT NULL, PRIMARY KEY (fdpk) ) ENGINE=INNODB; mysql> INSERT INTO tab_innodb (fdpk) VALUES (3);
각각의 테이블에 fdpk 라는 기본키( 유일성보장)를 생성후 3 를 insert 하였다.
# AUTO-COMMIT 활성화
mysql> SET autocommit=ON;
mysql> INSERT INTO tab_myisam (fdpk) VALUES (1), (2), (3);
mysql> INSERT INTO tab_innodb (fdpk) VALUES (1), (2), (3);
두 개의 스토리지엔진 결과를 비교해보자
mysql> INSERT INTO tab_myisam (fdpk) VALUES (1), (2), (3);
ERROR 1062 (23000): Duplicate entry '3' for key 'tab_myisam.PRIMARY'
mysql> INSERT INTO tab_innodb (fdpk) VALUES (1), (2), (3);
ERROR 1062 (23000): Duplicate entry '3' for key 'tab_innodb.PRIMARY'
mysql> SELECT * FROM tab_myisam;
+------+
| fdpk |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM tab_innodb;
+------+
| fdpk |
+------+
| 3 |
+------+
1 row in set (0.00 sec)
두 INSERT 문장 모두 프라리머리 키 중복 오류로 쿼리가 실패했다. 그런데 두 테이블의 레코드를 조회해조면 MySAM 테이블에는 오류가 발생했음에도 '1' 과 '2' 는 INSERT 된 상태로 남아 있는 것을 확인할 수 있다.
즉 MyISAM 테이블에 INSERT 문장이 실행되면서 차례대로 '1' 과 '2' 를 저장하고, 그 다음 '3'을 저장하려고 하는 순간 중복 키 오류(이미 '3' 이 존재) 가 발생한것이다. MyISAM 테이블에서 실행된 쿼리는 이미 INSERT 된 '1' 과 '2' 를 그대로 두고 쿼리 실행을 종료해 버린다.
이러한 현상을 부분 업데이트(Partial Update)라표현한다. 부분업데이트 현상은 테이블 데이터의 정합성을 맞추는데 상당히 어려운 문제를 만들어 낸다.
InnoDB 는 쿼리 중 일부라도 오류가 발생하면 전체를 원 상태로 만든다는 트랜잭션 원칙대로 INSERT 문장을 실행하지 전 상태로 그래도 복구했다.
5.1.2 주위사항
트랜잭션 또한 DBMS 의 커넥션과 동일하기 꼭 필요한 최소의 코드에만 적용하는 것이 좋다. 이는 프로그램 코드에서 트랜잭션의 범위를 최소화하라는 의미다.
- 다음 내용은 사용자가 게시판에 게시물을 작성한 후 저장 버튼을 클릭했을때 서버에서 처리하는 내용을 순서대로 정리한 것이다.
-
1) 처리 시작 -> 커넥션 생성 -> 트랜잭션 시작 2) 로그인 여부 확인 3) 글쓰기 오류 확인 4) 첨부로 업로드된 파일 저장 5) 사용자의 입력 내용을 DBMS에 저장 6) 첨부 파일 정보를 DBMS에 저장 7) 저장된 내용 또는 기타 정보를 DBMS에서 조회 8) 게시물 등록에 대한 알림 메일 발송 9) 알림 메일 발송 이력을 DBMS에 저장 10) 처리 완료 -> 트랜잭션 COMMIT -> 커넥션 반납
실제로 많은 개발자가 데이터베이스의 커넥션을 생성(또는 커넥션 풀에서 가져오는) 하는 코드를 1번과 2번 사이에 구현하면 그와 동시에 START TRANSACTION 명령으로 트랜잭셩을 시작한다. 그리고 9번과 10 번 사이에서 트랜잭션을 COMMIT 하고 커넥션을 종료(또는 커넥션풀로 반납)한다.
실제로 DBMS에 데이터를 저장하는 작업(트랜잭션)은 5번 부터 시작된다는 것을 알수 있다.
일반적으로 데이터베이스 커넥션은 개수가 제한적이어서 각 단위 프로그램이 커넥션을 소유하는 시간이 길어질수록 사용 가능한 여유커넥션의 개수는 줄어들것이다. 그리고 어느 순간에 각 단위 프로그램에서 커넥션을 가져가기 위해 기다려야 하는 상황이 발생할 수도 있다.
메일 전송이나 FTP 파일 전송 작업 또는 네트워크를 통해 원격 서버와 통신하는 등과 같은 작업은 어떻게 해서든 DBMS의 트랜잭션 내에서 제거하는 것이 좋다. 프로그램이 실행되는 동안 메일 서버와 통신할 수 없는 상황일 발생한다면 웹 서버뿐만 아니라 DBMS 서버까지 위험해지는 상황이 발생할 것이다.
사용자가 입력한 정보를 저장하는 5과 6번 작업은 반드시 하나의 트랜잭션으로 묶어야 하며, 7번 작업은 저장된 데이터의 단순 확인 및 조회이므로 트랜잭션에 포함할 필요는 없다. 9번 작업은 성격이 조금 다르기 때문에 이전 트랜잭션 (5, 6) 에 함께 묶지않아도 무방하다.
1. 처리 시작
2. 사용자의 로그인 여부 확인
3. 사용자의 글쓰기 내용의 오류 여부 확인
4. 첨부로 업로드된 파일 확인 및 저장
=> 데이터베이스 커넥션 생성 (또는 커넥션 풀에서 가져오기)
=> 트랜잭션 시작
5. 사용자의 입력 내용을 DBMS에 저장
6. 첨부 파일 정보를 DBMS에 저장
<= 트랜잭션 종료 (COMMIT)
7. 저장된 내용 또는 기타 정보를 DBMS에서 조회
8. 게시물 등록에 대한 알림 메일 발송 (= 네트워크 작업)
=> 트랜잭션 시작
9. 알림 메일 발송 이력을 DBMS에 저장
<= 트랜잭션 종료 (COMMIT)
<= 데이터베이스 커넥션 종료 (또는 커넥션 풀에 반납)
10. 처리 완료
프로그램의 코드가 데이터베이스 커넥션을 가지고 있는 범위와 트랜잭션이 활성화돼 있는 프로그램의 범위를 최소화해야 한다는 것이다. 또한 프로그램의 코드에서 라인 수는 한두 줄이라고 하더라도 네트워크 작업이 있는 경우에는 반드시 트랜잭션에서 배제해야한다. 그래야 DBMS 서버가 높은 부하 상태로 빠지거나 위험한 상태에 빠지는 경우를 예방할 수 있다.
'책 > Real MySQL 8.0 1권' 카테고리의 다른 글
[MySQL] B-Tree 인덱스 (0) | 2024.10.07 |
---|---|
[Real Mysql 8.0] 5.2 MySQL 엔진의 잠금 (1) | 2024.10.02 |