스프링 DB 1편

한상우·2023년 5월 31일
0

spring

목록 보기
4/5

스프링 DB 1편

JDBC

애플리케이션 서버와 DB의 일반적인 사용법은

  1. DB와 커넥션 연결
  2. DB에게 SQL 전달
  3. DB가 결과 응답

각각의 데이터베이스마다 커넥션을 연결하는 방법, SQL을 전달하는 방법, 그리고 결과를 응답 받는
방법이 모두 다르다

등장 이유: 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API

자바는 표준 인터페이스를 정해뒀기에 개발자는 표준 인터페이스를 사용해서 개발하면 됨

JDBC 드라이버: JDBC 인터페이스를 각각의 DB 벤더 (회사)에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공

최신데이터

  • JDBC는 복잡하고 오래되었다. 최근에는 JDBC를 직접 사용하는 것이 아닌 편리하게 사용하게 하는 다양한 기술이 존재
  • SQL Mapper (MyBatis) : 개발자가 SQL을 직접 작성해야함
  • ORM (JPA) : ORM기술이 SQL을 동적으로 생성

DriverManager

  • JDBC가 기본으로 제공
  • 라이브러리에 등록되어 있는 드라이버를 관리, 커넥션 획득

참고로 커넥션은 꼭 끊어줘야 한다. 안해주면 리소스 누수가 발생하여 커넥션 부족으로 인한 장애가 발생할 수 있다


커넥션 풀

  1. 커넥션 조회

  2. TCP/IP 커넥션 획득

  3. ID, PW 부가정보 전달

    이후 , DB 내부 인증 + DB 세션 생성

  4. 커넥션 생성 완료

  5. 커넥션 반환

커넥션은 이와 같은 과정을 거치기에 복잡하고 시간이 많이 소비된다

이를 해결하기 위해 커넥션 풀 이라는 방법 도입, 커넥션을 미리 생성해두고 사용

커넥션 풀에 들어있는 커넥션들은 TCP/IP 연결이 되어있는 상태이기에 즉시 SQL을 DB에 전달 가능

커넥션을 사용하고 나면 종료하는게 아닌 풀에 반환!!

스프링 부트 2.0 부터는 기본 커넥션 풀로 hikariCP 를 제공 (오픈소스)

DataSource

  • 커넥션을 획득하는 방법 추상화
  • DriverManager를 통해서도 커넥션 획득할 수 있음. 매번 커넥션 연결을 통해
  • DriverManager는 DataSource인터페이스를 사용하지 않기에 둘을 모두 구현한 DriverManagerDataSource 제공

트랜잭션 이해

데이터베이스에서 트랜잭션은 하나의 거래를 안전하게 처리하도록 보장해주는 것을 뜻함

모든 작업이 정상적으로 처리되어 DB에 반영되면 커밋

실패해서 거래 이전으로 돌리는 것을 롤백 이라 한다

클라이언트와 DB가 커넥션을 맺을 떄 내부에 DB 세션을 만든다. 이후 해당 커넥션을 통한 모든 요청은 이 세션을 통해 실행된다

자동 커밋, 수동 커밋

  • 자동 커밋: 쿼리 실행 직후 자동으로 커밋 호출, 트랜잭션 기능 사용 불가
  • 수동 커밋: 커밋 롤백 직접 호출해야 함

자동 커밋 모드에서 수동 커밋 모드로 전환 하는 것을 트랜잭션을 시작한다고 표현한다고 함

DB 락

  • 세션이 트랜잭션을 시작하고 데이터를 변경하는 동안 커밋이나 롤백 전까지 다른 세션이 해당 데이터를 변경할 수 없음
  • 보통 데이터를 조회할 때는 락이 걸리지 않지만, select for update 를 쓰면 락을 획득할 수 있음
  • 락이 걸렸을 때 다른 세션이 접근할 수 없음. 타임 아웃이 걸려있다.

스프링과 트랜잭션

애플리케이션 구조를 Controller - Service - Repository 로 나눈다면

  • Controller는 스프링 MVC 기술을 사용
  • Service는 순수한 자바 코드
  • Repository는 DB에 접근하는 기술 (JDBC, JPA)을 사용

이때 서비스 계층은 최대한 순수한 자바 코드로 작성해야 추후 UI 단이나 DB 단에서 변경이 일어나도 코드 수정 없이 유지가 될 수 있다

MemberServiceV2 코드에서는 트랜잭션을 서비스 단에서 시작해야 함으로 트랜잭션을 서비스 계층에서 시작했는데, JDBC 기술에 의존하게 되었다

지금까지의 문제점

  1. 서비스 계층에서 JDBC 의존
  2. 같은 트랜잭션 유지 위해 파라미터로 커넥션을 넘김
  3. 트랜잭션에 try catch finally 반복이 많다
  4. SQLException 을 던져버리는데 이 역시 JDBC의 예외, JPA는 다르다 (JDBC 의존)

해결

트랜잭션 추상화

  • 인터페이스 PlatformTransactionManager (트랜잭션 매니저)

  • 트랜잭션 매니저는 추상화 기능도 제공하지만, 동기화 기능도 제공한다, 이전에 파라미터로 넘기던걸 트랜잭션 동기화 매니저를 통해 사용

  • 트랜잭션 동기화 매니저: 내부에서 쓰레드 로컬을 사용하기 때문에, 멀티 쓰레드 환경에서 안전하게 커넥션 동기화 가능 (뒤에서 자세히 배운다)

    1. 서비스 계층에서 트랜잭션 매니저.getTransaction 을 통해 트랜잭션 시작

    2. 트랜잭션 매니저가 내부에서 DataSource 를 통해 커넥션 만들어

    3. 수동 커밋 모드로 만든 커넥션을 트랜잭션 동기화 매니저에 보관

    4. 리포지토리는 보관된 커넥션을 사용 (파라미터로 전달 안해도 됨)

    5. DataSourceUtils.getConnection 를 통해 보관된 커넥션을 가져오고

    6. 획득한 커넥션을 통해 SQL을 DB에 전달

    7. 처리 후 트랜잭션을 종료하기 위해 동기화 된 커넥션을 동기화 매니저에서 획득한다

    8. 커밋이나 롤백을 진행

    9. 트랜잭션 동기화 매니저를 정리하고, con.close 로 커넥션을 종료한다

      Repository 부분

      DataSourceUtils.getConnection 를 통해 보관된 커넥션을 가져오고

      DataSourceUtils.releaseConnection

      로 트랜잭션 유지를 위해 커넥션을 닫지 않고 유지한다

      만약 동기화 매니저가 관리하는 커넥션이 없을 경우에 커넥션을 닫는다

      Service 부분

      private final PlatformTransactionManager transactionManager를 통해 트랜잭션 매니저를 주입 받는다.


스프링 고급 학습 후 다시 보기

profile
안녕하세요 ^^

0개의 댓글