0+ 스프링/0+스프링 DB

[스프링 DB] 데이터를 저장할 때 파일에 저장해도 되는데, 데이터베이스에 저장하는 이유?

힘들면힘을내는쿼카 2023. 7. 6. 16:54
728x90
반응형

[스프링 DB] 데이터를 저장할 때 파일에 저장해도 되는데, 데이터베이스에 저장하는 이유?

 

개발을 하면 자연스럽게 데이터베이스와 연동하여 데이터를 저장, 수정, 삭제, 조회 합니다.


데이터를 저장할 때 파일에 저장해도 되는데, 데이터 베이스에 저장하는 이유가 무엇일까요? 🤔

 

가장 큰 이유는 바로 데이터베이스는 트랜잭션이라는 개념을 지원하기 때문입니다.!!!!!

 

트랜잭션?

트랜잭션(Transaction)을 번역하면 “거래” 라는 의미 입니다.
데이터베이스에서 트랜잭션은 하나의 “거래”를 안전하게 처리하도록 보장해주는 것을 의미합니다.


다시 말하면 작업의 완전성을 보장해주는 것 입니다.

 

 

참고
트랜잭션은 하나의 Connection을 가져와 사용하다가 닫는 사이에 발생합니다.
트랜잭션의 시작종료Connection객체를 통해 이뤄지기 때문입니다.

 

커밋과 롤백

커밋
트랜잭션 시작과 종료사이에 아무 문제가 발생하지 않는다면 이를 확정지어 데이터베이스에 반영합니다.
이를 커밋(commit)이라고 합니다.

 

롤백
데이터 베이스가 제공하는 트랜잭션 기능을 이용하면
트랜잭션 시작과 트랜잭션 종료 사이에 중간에 하나라도 실패하면 거래 전의 상태로 돌아 갈 수 있습니다.

즉 방금 발생한 작업을 무효화 하는 것 입니다.
이것을 롤백(rollback)이라고 부릅니다.

 

정리

  • 트랜잭션: 작업의 완전성을 보장해주는 것
    • 논리적인 작업 셋을 모두 완벽하게 처리하거나,
    • 처리하지 못할 경우에는 원상태로 복구하여 작업의 일부만 적용되는 현상이 발생하지 않도록 만들어주는 기능
  • commit: 모든 작업이 성공해서 데이터베이스에 반영하는 것
  • rollback: 작업 중 하나라도 실패해서 거래 이전으로 되돌리는 것

 

트랜잭션 ACID

트랜잭션은 원자성(Atomicty), 일관성(Consistency), 격리성(Isolation), 지속성(Durability) 4가지를 모두 보장해야 합니다.

 

원자성

트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공하거나 모두 실패해야 합니다.

 

일관성

모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 합니다.
(데이터베이스에서 정한 무결성 제약 조건을 항상 만족)

 

격리성

동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리해야 합니다.
(트랜잭션 격리 수준(Isolation level)을 선택)

e.g) 동시에 같은 데이터를 수정하지 못하도록 막는다.

 

트랜잭션 격리 수준 - Isolation level
하나의 트랜잭션 내에서 또는 여러 트랜잭션 간의 작업 내용을 어떻게 공유하고 차단할 것인지 결정하는 레벨

1. READ UNCOMMITED(커밋되지 않은 읽기)
2. READ COMMITTED(커밋된 읽기)
3. REPEATABLE READ(반복 가능한 읽기)
4. SERIALIZABLE(직렬화 가능) 

 

지속성

트랜잭션을 성공적으로 마치면 그 결과가 항상 기록되어야 합니다.
중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용하여 성공한 트랜잭션을 복구해야 합니다.

 

트랜잭션 사용법

트랜잭션 시작과 종료 사이에 실행한 작업은 하나의 작업인 것처럼 모두 성공하거나 모두 실패해야 합니다.
따라서 자동 커밋 모드를 사용하면 안됩니다.!!

중간에 실패를 하면 트랜잭션 이전 상태로 되돌려야 하는데,
자동 커밋 모드이면 실패전에 발생한 쿼리는 커밋되어버리기 때문입니다.

 

이때 중요한것이 있는데,
애플리케이션에 DB 트랜잭션을 사용하기 위해서는
트랜잭션을 사용하는 동안 같은 커넥션을 유지 해야 합니다.

 

커밋
트랜잭션을 데이터베이스에 반영

 

롤백
트랜잭션 시작 전 상태로 데이터베이스를 복구

 

트랜잭션 사용

// 커넥션 획득
Connection con = dataSource.getConnection();

try {
    // 트랜잭션 시작
    con.setAutoCommit(false);

    // .. 비지니스 로직 .. //

    // 커밋
    con.commit();
} catch(Exception e) {
    // 롤백
    con.rollback();
} finally {
    if (con != null) {
        try {
            con.setAutoCommit(true); //커넥션 풀 고려 
          con.close();
        } catch (Exception e) {
            log.info("error", e);
        }
    } 
}

 

참고
일반적으로 자동 커밋 모드에서 수동 커밋 모드로 전환하는 것을 트랜잭션을 시작한다고 합니다.

 

트랜잭션을 최소화 해라

트랜잭션 또한 DBMS의 커넥션과 동일하게 최소의 코드에만 적용하는 것이 좋습니다.
다시 말하면 트랜잭션의 범위를 최소화하라는 의미 입니다.

 

문제 로직
만약 아래와 같은 기능을 갖고있는 메소드가 있다고 합시다.

// 커넥션 생성
// 트랜잭션 시작

1. 로그인 여부 확인
2. 게시물 입력 데이터 검증
3. 게시물 첨부 파일 확인 및 저장
4. 게시물 입력 데이터 DBMS에 저장
5. 게시물 첨부 파일 정보 DBMS에 저장
6. 게시물 등록에 대한 알림 메시지 발송
7. 알림 메시지 이력 DBMS에 저장

// 트랜잭션 종료(커밋)
// 커넥션 반납

 

과연 모든 과정에서 DB의 트랜잭션이 필요할까요? 🤔

먼저 1, 2, 3과정은 트랜잭션에 포함시킬 이유는 없습니다.

 

실제로 DBMS에 저장하는 것은 4, 5, 7번 과정만 있습니다.
특히 4, 5는 반드시 동일한 트랜잭션에서 수행되어야 하는 것을 확인 할 수 있습니다.

 

6번과 같은 로직은 치명적 입니다.
네트워크를 통해 원격 서버와 통신하는 작업은 DBMS의 트랜잭션에서 제거하는 것이 좋습니다.

 

최적화 로직
위 과정을 최적화하면 아래와 같습니다.

1. 로그인 여부 확인
2. 게시물 입력 데이터 검증
3. 게시물 첨부 파일 확인 및 저장

// 커넥션 생성
// 트랜잭션 시작
4. 게시물 입력 데이터 DBMS에 저장
5. 게시물 첨부 파일 정보 DBMS에 저장
// 트랜잭션 종료(커밋)

6. 게시물 등록에 대한 알림 메시지 발송

// 트랜잭션 시작
7. 알림 메시지 이력 DBMS에 저장
// 트랜잭션 종료(커밋)
// 커넥션 반납

 

정리

  • 트랜잭션은 작업의 완전성을 보장해주는 것을 의미한다.
    • 커밋: 작업 내용을 DBMS에 반영
    • 롤백: 작업 중간에 실패가 발생하면 트랜잭션 이전의 상태로 복구
  • 트랜잭션이 활성화돼 있는 범위를 최소화 하자.
  • 로직에 네트워크 작업이 있는 경우 반드시 트랜잭션에서 배재하자.

 

참고

 

 

728x90
반응형