포스트

Day06 AI 코딩자동화 툴,

코딩자동화 툴

Github Copilot

Cursor

JPA심화 - 트렌젝션, 락

1.실습 파일 세팅하기

1) 도커 마리아DB 컨테이너 실행하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
```bash
docker run -p 3306:3306 --name maria_container -e MARIADB_ROOT_PASSWORD=1234 -d mariadb
``` 2) yml 파일 세팅하기
```yml
spring:
datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306/exam_db
    username: root
    password: 1234
jpa:
    database-platform: org.hibernate.dialect.MariaDBDialect
    hibernate:
        ddl-auto: create
    properties:
        hibernate:
            show_sql: true
            format_sql: true
            use_sql_comments: true
``` 3) 기타 프로젝트 파일 세팅하기 
- [GIT](https://github.com/sik2/jpa-level-up2501/commit/main#diff-14c51ae2daa33833252d80597ff48d8e8970766920d0d020d5897ca54553611eR12)

2. docker 로그 설정

1) 도커 컨테이너 실행하기

  • 컨테이너 접속하기
    1
    
      docker exec -it mysql-container bash
    
  • 마리아DB 접속하기
    1
    
      mariadb -u root -p
    

    2) 마리아DB 로그 설정변경

      SET GLOBAL general_log = 'ON';
      SET GLOBAL general_log_file = '/var/lib/mysql/mariadb.log';
    

    3) 로그 확인 하기

  • 파일경로 확인하기
    1
    
      ls /var/lib/mysql/
    
  • 로그 확인하기
    1
    
      tail -f /var/lib/mysql/mariadb.log
    

    4) 로그 출력

  • localHost에서 get요청을 날리면 컨테이너에 로그가 남겨진다.
    1
    2
    3
    4
    
      250107  6:07:49    122 Query    set autocommit=0
                      122 Query    select p1_0.id,p1_0.chatcontent,p1_0.chatsubject,p1_0.username from post p1_0 where p1_0.id=1
                      122 Query    COMMIT
                      122 Query    set autocommit=1
    

3. 트렌젝션

1) 트렌젝션

  • 데이터베이스의 상태를 변화시키기 위한 작업의 단위
  • 여러 쿼리를 하나의 단위로 묶어서 처리하는 것
  • 트렌젝션의 원자성, 일관성, 독립성, 지속성을 보장하는 것 2) 트렌젝션 예시
  • 송금 3) 내장된 트랜젝션
  • 내장된 예약어에 대해서는 autocommit 을 제공한다.
    1
    2
    3
    4
    
      250107  6:29:06    132 Query    set autocommit=0
                      132 Query    select p1_0.id,p1_0.chatcontent,p1_0.chatsubject,p1_0.username from post p1_0 where p1_0.id=1
                      132 Query    COMMIT
                      132 Query    set autocommit=1
    
  • Repository에 커스텀한 메서드는 트랜젝션이 없다.
    1
    
      250107  6:28:28    132 Query    /* <criteria> */ select p1_0.id,p1_0.chatcontent,p1_0.chatsubject,p1_0.username from post p1_0 where p1_0.username='kkddanks'
    
  • Service단에서 @Transactional 어노테이션을 추가하여 하나의 단위로 관리한다.
    1
    2
    3
    4
    
      250107  6:33:23    142 Query    set autocommit=0
                      142 Query    /* <criteria> */ select p1_0.id,p1_0.chatcontent,p1_0.chatsubject,p1_0.username from post p1_0 where p1_0.username='kkddanks'
                      142 Query    COMMIT
                      142 Query    set autocommit=1
    

4. 락

1. 락의 개념

  • 데이터베이스에서 데이터를 보호하기 위해 사용되는 기능
  • 데이터베이스 트랜젝션이 동시에 여러 사용자에게 영향을 미치는 것을 방지하는 것
  • 락은 데이터베이스 트랜젝션이 동시에 여러 사용자에게 영향을 미치는 것을 방지하는 것

2. 읽기락

  • 데이터 조회는 가능하지만 수정은 못하게 막는 것 1) sql에서 락 걸기
    • sample 데이터 준비
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
        DROP DATABASE IF EXISTS exam_db;
        CREATE DATABASE exam_db;
        USE exam_db;
      
        CREATE TABLE post (
                            id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
                            username VARCHAR(100) NOT NULL,
                            content VARCHAR(1000) NOT NULL,
                            subject VARCHAR(100) NOT NULL
        );
      
        INSERT INTO post
        SET username = '홍길동',
            content = '내용',
            subject = '제목';
      
      
    • 일기 락 걸기
      1
      2
      3
      
        START TRANSACTION;
      
        SELECT * FROM post WHERE id = 1 LOCK IN SHARE MODE;
      
    • 데이터 조회는 가능하다.
      1
      
        SELECT * FROM post where id =1;
      

      image

    • 데이터 변경은 불가능하다.
      1
      2
      3
      
        UPDATE post
        SET username = '홍길순'
        WHERE id = 1;
      

      image

2) spring에서 락 걸기

  • 깃코드

    • 코드의 진행순서
      1. Controller에서 Service 메서드 호출
      2. @Transactional이 있으므로 트랜잭션 시작
      3. Repository 메서드 호출 시 @Lock(LockModeType.PESSIMISTIC_READ) 작동
      4. 이때 DB에 share lock 설정됨
      5. Thread.sleep(10000) 동안 lock 유지
      6. 두 번째 repository 호출도 같은 트랜잭션 내에서 실행
      7. Service 메서드 종료되면서 트랜잭션도 종료
      8. 이때 lock도 함께 해제
    • 트랜잭션 A (share lock 획득) -> sleep 10초 —–> 종료
    • 트랜잭션 B (lock 획득 시도) —–> 대기 —–> A 종료 후 실행

3. 쓰기락

  • 1) sql에서 락 걸기
  • sample 데이터 준비
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      DROP DATABASE IF EXISTS exam_db;
      CREATE DATABASE exam_db;
      USE exam_db;
    
      CREATE TABLE post (
          id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
          username VARCHAR(100) NOT NULL,
          content VARCHAR(1000) NOT NULL,
          subject VARCHAR(100) NOT NULL
      );
    
      INSERT INTO post
      SET username = '홍길동',
          content = '내용',
          subject = '제목';
    
  • 쓰기 락 걸기
    1
    2
    3
    
      SET autocommit = 0;
    
      SELECT * FROM post WHERE id = 1 FOR UPDATE;
    
  • 1번 글 읽기 FOR UPDATE, 락 발생
    1
    2
    3
    
      USE exam_db;
    
      SELECT * FROM post WHERE id = 1 FOR UPDATE;
    
  • 1번 글 변경 트랜잭션 COMMIT 및 종료, 순서 3에서 걸린 락이 해제됨
    1
    2
    3
    4
    5
    6
    
      UPDATE post
      SET username = '홍길순'
      WHERE id = 1;
    
      COMMIT;
      SET autocommit = 1;
    
  • 발생한 락이 해제되었는지 확인
    1
    
      SELECT * FROM post WHERE id = 1 FOR UPDATE;
    

2. JPA에서 락 걸기

  • 깃코드

    • 코드의 진행순서
      1. Controller에서 Service 메서드 호출
      2. @Transactional이 있으므로 트랜잭션 시작
      3. Repository 메서드 호출 시 @Lock(LockModeType.PESSIMISTIC_WRITE) 작동
      4. 응답을 반환하고 트랜잭션이 종료될 때 락 해제
    • 첫 번째 트랜잭션이 완전히 종료될 때까지 대기
    • 타임아웃(기본 값)까지 대기 후 락을 획득하지 못하면 예외 발생
    • 콘솔창에 forUpdate 쿼리가 날라간다. image
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.