[DB | SQL] Transaction, Commit, Rollback

JTI·2023년 5월 28일
0

🗂️ DB | SQL

목록 보기
4/5
post-thumbnail

💡 트랜잭션(Transaction)


✔️ 더이상 나눌 수 없는 작업의 단위

  • insert, update, select 등 명령 하나하나가 Transaction이다.
    : 나눠지지 않기 때문

  • 계좌이체의 경우, 출금과 입금이 하나의 트랜잭션으로 묶여야 된다.

  • 만약 출금, 입금 둘다 각각의 트랜잭션을 가지고 있다면?
    ➡️ 출금은 성공했는데 입금에 실패했다하면 출금만 되고 입금이 안되는 것이다. 즉, 나는 돈을 보냈는데 상대방은 돈을 받지 못하는 상황이 되어버린 것이다.
    ➡️ 둘 중 하나라도 되지 않으면 출금하기 전으로 돌아가서(트랜잭션이 시작하기 전) Rollback을 해줘야 한다. 원래대로 돌아가야 한다.
    ➡️ 모 아니면 도: 출금과 입금이 모두 성공하지 않으면 실패

  • 둘 이상의 작업을 어떻게 하나의 트랜잭션으로 묶는지 알아보자!


⚙️ Transaction의 속성: ACID

📌 원자성(Atomicity)

✔️ 나눌 수 없는 하나의 작업으로 다뤄져야 한다.

  • 계좌이체 = 출금 + 입금
    : 두 개의 작업은 하나의 작업으로 다뤄져야 함

📌 일관성(Consistency)

✔️ 트랜잭션 수행 전과 후가 일관된 상태를 유지해야 한다.

  • A 계좌에 500만원, B 계좌에 300만원이 있다고 치자, A가 B에게 200만원을 보내면 B는 500만원이 돼야 하고 A는 300만원이 돼야 한다.
    ➡️ 각각의 결과가 알맞게 떨어져야 한다.

📌 고립성(Isolation)

✔️ 각 트랜잭션은 독립적으로 수행되어야 한다.

  • 각 트랜잭션이 영향을 받지 않아야 함

  • Isolation Level
    : 어느정도 영향을 끼치는 정도
    : 레벨이 꼭 높다고 좋은 것은 아님
    ➡️ 작업에 따라 적절하게 처리해야 함

📌 영속성(Durability)

✔️ 성공한 트랜잭션의 결과는 유지되어야 한다.

  • 계좌이체가 됐으면 그 결과가 계속 유지되어야 한다.

💡 Commit & Rollback


✔️ Commit
: 작업 내용을 DB에 영구적으로 저장

✔️ rollback
: 최근 변경사항을 취소(마지막 커밋으로 복귀)

  • 실수로 일을 잘못 처리했다면 rollback해서 처리한다.

📎 자동 commit | 수동 commit

✔️ AutoCommit
: 명령 실행 후, 자동으로 커밋이 수행(rollback 불가)

✔️ AutoCommit 해제: 수동 commit
: 명령 실행 후, 명시적으로 commit 또는 rollback을 입력

  • SET autocommit = 0;

📎 Transaction의 isolation level

✔️ 각 트랜잭션을 고립시키는 정도를 4가지로 나눔
✔️ 트랜잭션의 종류에 따라서 4가지의 레벨을 선택할 수 있다.

📌 READ UNCOMMITED

  • 커밋되지 않은 데이터도 읽기 가능

  • Tx1이 하는 작업에 Tx2가 영향을 줬다.
    ➡️ isolation level이 굉장히 낮음

  • dirty read 라고도 불림
    : 다른 사람이 손대서 더러워졌다는 의미

📌 READ COMMITED

  • 커밋된 데이터만 읽기 가능

  • Tx1 입장에서는 없던 데이터가 갑자기 나타남
    ➡️ Phantom read라고도 불림

📌 REPEATABLE READ (defalut)

  • 트랜잭션이 시작된 이후 변경은 무시됨

  • 반복해서 읽을 수 있다는 뜻
    : 다른 트랜잭션에서 아무리 데이터를 넣고 커밋을 해도 해당 트랜잭션에서는 같은 결과만 나옴

📌 SERIALZABLE

  • 한번에 하나의 트랜잭션만 독립적으로 수행

  • 고립도 최상

  • 각 트랜잭션이 하나도 겹치지 않고 고립적으로 수행 ➡️ 직렬
    : 트랜잭션은 좀 겹치게 움직여야 함(병렬). 그래야 적은 하드웨어 저장으로 많은 사람들이 사용할 수 있다. 하지만 데이터의 품질이 떨어질 수 있다.

  • 데이터가 절대로 엉키면 안되고 중요한 트랜잭션으로 처리해야 한다면 SERIALZABLE 을 써야 한다.
    ➡️ 성능 ⬇️ 품질 ⬆️

  • Tx1에서 누가 읽어오는 작업을 하고 있는데 Tx2에서 Insert를 했다. 그럼 바로 넣어지지 않고 대기 상태가 된다. Tx1에서 commit을 해서 작업이 다 끝나야 대기 상태가 풀리고 그때서야 들어가게 된다.

✏️ sql Workbencher로 테스트 해보기

✏️ java 코드로 테스트 해보기

	@Test
    public void transactionTest() throws Exception {
        int rowCount = 0;
        Connection connection = null;

        try {
            deleteAll();
            connection = dataSource.getConnection();
            // 여러개의 문장을 하나의 트랜잭션에 묶을 수 있게 수동 commit으로 바꿈
            connection.setAutoCommit(false);

            String sql = "insert into user_info values (?, ?, ?, ?, ?, ?, now())";

            // 1번째 테스트
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, "asdf9");
            preparedStatement.setString(2, "1234");
            preparedStatement.setString(3,"aaa");
            preparedStatement.setString(4, "aaa@aaa.com");
            preparedStatement.setDate(5, new java.sql.Date(new Date().getTime()));
            preparedStatement.setString(6, "faceBook");
            rowCount = preparedStatement.executeUpdate();

            // 2번째 테스트
            preparedStatement.setString(1, "asdq");
            rowCount = preparedStatement.executeUpdate();

            // 둘 중에 하나라도 false가 되면 예외가 뜬다.
            connection.commit();
        } catch (Exception e) {
            connection.rollback();
        } finally {
        }
    }

profile
Fill in my own colorful colors🎨

0개의 댓글