1. MySQL에서의 트랜잭션
    1. 트랜잭션이란

      1. 하나의 논리적인 작업에 대해 쿼리가 몇개이든 상관없이 논리적인 작업 하나가 100% 적용되거나 아예 적용되지 않아야 함을 보장해주는 것
    2. 예시 코드

      // MyISAM 스토리지 엔진 기반 테이블
      CREATE TABLE tab_myisam (fdpk int not null, primary key(fdpk) ENGINE=MyISAM;
      INSERT INTO tab_myisam (fdpk) VALUES (3); 
      
      // InnoDB 스토리지 엔진 기반 테이블
      CREATE TABLE tab_innodb (fdpk int not null, primary key(fdpk) ENGINE=InnoDB;
      INSERT INTO tab_innodb (fdkp) VALUES (3);
      
      SET autocommit=ON;
      
      // MyISAM 스토리지 엔진 사용 테이블 INSERT
      INSERT INTO tab_myisam (fdpk) VALUES (1),(2),(3);
      // InnoDB 스토리지 엔진 사용 테이블 INSERT
      INSERT INTO tab_innodb (fdpk) VALUES (1),(2),(3);
      
    3. 결과

      1. tab_myisam 테이블에는 1, 2, 3의 값을 가지고 있으며, tab_myisam 테이블에는 3의 값만 가지고 있게 됨
      2. 과정을 살펴보면 두 테이블 모두 테이블을 생성하고 fdpk로 3을 넣어뒀다
      3. INSERT에서 fdpk로 1, 2, 3 을 넣게되는데
      4. MyISAM 스토리지 엔진의 경우 1, 2의 값을 넣고 마지막 3의 값을 넣는 과정에서 중복키 오류로 인서트가 안됨
      5. 하지만 MyISAM은 트랜잭션을 지원하지 않기 때문에 1, 2, 3의 값을 가지게 됨
      6. InnoDB 스토리지 엔진의 경우 INSERT 실행 과정에서 중복키 에러가 발생했을 때 트랜잭션에 의해 일부라도 오류가 생긴 경우 모두 롤백하도록 설계
      7. 따라서 InnoDB 스토리지 엔진 테이블의 경우 초기값인 3만 남아있게 되고 INSERT를 실행했던 부분은 모두 취소가 이루어짐
      8. MyISAM처럼 트랜잭션을 지원하지 않는 경우 실패한 쿼리에 의해 남은 데이터를 삭제를 하는 이중작업을 발생시킬 수 있는 것임
    4. 주의 사항

      1. 트랜잭션은 가능한 작은 단위로 잡아햐 함
      2. 커넥션의 개수는 제한적 → 커넥션 소유시간 길어지면 다른 작업이 커넥션을 기다려야함
      3. 메일 전송, FTP 파일 전송 등의 작업은 어떻게 해서든 DBMS의 트랜잭션 내에서 제거하는 것이 좋음
      4. 프로그램이 실행되는 동안 전송할 수 없는 상황이 된다면, 웹 뿐만 아니라 DBMS 서버까지 위험해질 수 있음
  2. MySQL 엔진의 잠금
    1. MySQL의 잠금은 크게 스토리지 엔진 레벨, MySQL 엔진 레벨로 나눌 수 있음

    2. MySQL 엔진은 스토리지 엔진을 제외한 나머지 부분

    3. MySQL 엔진의 잠금은 모든 스토리지 엔진에 영향을 미치지만 스토리지 엔진의 잠금은 스토리지 엔진 간 영향을 받지 않음

    4. MySQL 엔진은 테이블 데이터 동기화를 위한 테이블 락 이외에 테이블의 구조를 잠그는 메타데이터 락, 사용자 필요에 맞게 사용할 수 있는 네임드 락 잠금 기능도 제공

    5. 글로벌 락

      1. FLUSH TABLES WITH READ LOCK; 명령으로 획득 가능
      2. MySQL에서 제공하는 잠금 범위 중 가장 넓은 범위, 한 세션에서 획득하면 다른 세션에서 SELECT를 제외한 대부분의 DDL, DML 문장을 실행하는 경우 대기 상태
      3. 영향 범위는 MySQL 서버 전체, 테이블/데이터베이스가 다르더라도 영향을 미침
      4. MyISAM, MEMORY 테이블에 대해 mysqldump로 일관된 백업을 받을 때 글로벌 락 사용
      5. 일단 명령어에서 처럼 FLUSH를 먼저 하기 때문에 해당 명령을 실행하더라도 먼저 실행된 쿼리가 종료된 후에 글로벌 락 작동
      6. 위 경우 때문에 시간이 오래 걸리는 쿼리 + 글로벌 락의 조합으로 오랜 시간 동안 INSERT, UPDATE, DELETE가 불가능한 상황이 생길 수 있음
      7. InnoDB의 경우 트랜잭션을 지원하기 때문에 일관된 상태를 위해 모든 데이터 변경을 멈출 필요는 없음
      8. MySQL 8.0부터는 백업 툴들의 안정성을 위해 백업 락 도입
        1. 특정 세션이 백업 락을 획득하면, 모든 세션에서 테이블 스키마, 사용자의 인증 관련 정보를 변경할 수 없게 됨
        2. 하지만 백업 락은 일반적인 테이블의 변경은 허용
        3. 주로 백업은 Slave 서버에서 실행
    6. 테이블 락

      1. 개별 테이블 단위로 잠금을 설정하도록 함
      2. LOCK TABLES table_name [ READ | WRITE ]; 명령으로 특정 테이블 락 획득 가능
      3. 테이블 락은 MyISAM 뿐만 아니라 InnoDB 스토리지 엔진을 사용하는 테이블도 동일하게 설정 가능
      4. UNLOCK TABLES; 명령으로 잠금을 반납
      5. 위처럼 명령어를 통해 락을 걸고 반납하는 작업은 사용할 필요가 거의 없음, 글로벌 락과 동일하게 온라인 작업에 상당한 영향을 미치기 때문에 사용에 주의
      6. 위처럼 명령어를 입력하여 락을 얻는 방식을 명시적 테이블 락이라고 함
      7. 묵시적인 테이블 락은 MyISAM, MEMORY 테이블에 데이터를 변경하는 쿼리 실행하면 발생
      8. 서버가 데이터가 변경되는 동안 잠금을 설정하고, 데이터를 변경한 후 잠금을 해제하는 방식
      9. 하지만, InnoDB의 경우, 테이블이 아닌 레코드 기반의 잠금을 사용하기 때문에 단순 데이터 변경 쿼리로 인해 묵시적인 테이블 락이 설정되지는 않음
      10. 더 정확하게는 InnoDB도 테이블 락은 설정되지만, DML 쿼리에 대해서는 락인 걸리지 않고 DDL 쿼리에 대해서만 적용
    7. 네임드 락

      1. GET_LOCK() 함수를 이용해 임의의 문자열에 대해 잠금을 설정할 수 있음

      2. 이 잠금의 특징은 대상이 테이블, 레코드, AUTO_INCREMENT와 같은 데이터베이스 객체가 아니라는 점이다

      3. 네임드 락은 단순히 사용자가 지정한 문자열에 대해 획득하고 반납하는 잠금

      4. 데이터베이스 서버 1대에 5대의 웹 서버가 접속해서 서비스하는 상황에서 5대의 웹 서버가 어떤 정보를 동기화해야 하는 요건처럼 여러 클라이언트가 상호 동기화를 처리해야 할 때 사용함(많이 사용되는 기능 아님)

        // "mylock"이라는 문자열에 대해 잠금을 획득
        // 이미 잠금을 사용하면 2초동안 대기(2초 이후 자동으로 잠금 해제)
        SELECT GET_LOCK('mylock', 2);
        
        // "mylock"이라는 문자열에 대해 잠금이 설정돼 있는지 확인
        SELECT IS_FREE_LOCK('mylock');
        
        // "mylock"이라는 문자열에 대해 획득했던 잠금을 반납
        SELECT RELEASE_LOCK('mylock');
        
        // 3개 함수 모두 정상적으로 락을 획득하거나 해제한 경우에는 1을
        // 아니면 NULL 또는 0을 반환
        
    8. 메타데이터 락

      1. 데이터베이스 객체(테이블, 뷰 등)의 이름이나 구조를 변경하는 경우에 획득하는 잠금

      2. 메타데이터 락은 명식적으로 획득/해제할 수 있는 것이 아니며, 테이블 이름을 변경하는 경우 자동으로 획득하는 잠금4

      3. RENAME TABLE 명령을 실행하는 경우 원래 이름과 변경될 이름 두 개 모두 한꺼번에 잠금을 설정

      4. 실시간으로 테이블을 바꿔야 하는 요건이 배치 프로그램에서 자주 발생하는데, 이에 메타데이터 락이 발생

        // 배치 프로그램에서 별도의 임시 테이블(rank_new)에 서비스용 랭킹 데이터를 생성
        
        // 랭킹 배치가 완료되면 현재 서비스용 랭킹 테이블(rank)을 rank_backup으로 백업
        
        // 새로 만들어진 랭킹 테이블(rank_new)을 서비스용으로 대체하고자 하는 경우
        
        RENAME TABLE rank TO rank_backup, rank_new TO rank;
        
        RENAME TABLE rank TO rank_backup;
        RENAME TABLE rank_new TO rank;
        
      5. 때로는 메타데이터 잠금과 InnoDB의 트랜잭션을 동시에 사용해야 하는 경우도 존재

        CREATE TABLE access_log (
        	id BIGINT NOT NULL AUTO_INCREMENT,
        	client_id INT UNSIGNED,
        	access_dttm TIMESTAMP,
        	...,
        	PRIMARY KEY(id)
        );
        
      6. 어느날 위 테이블 구조를