애플리케이션 서버와 DB의 일반적인 사용법은
각각의 데이터베이스마다 커넥션을 연결하는 방법, SQL을 전달하는 방법, 그리고 결과를 응답 받는
방법이 모두 다르다
등장 이유: 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API
자바는 표준 인터페이스를 정해뒀기에 개발자는 표준 인터페이스를 사용해서 개발하면 됨
JDBC 드라이버: JDBC 인터페이스를 각각의 DB 벤더 (회사)에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공
참고로 커넥션은 꼭 끊어줘야 한다. 안해주면 리소스 누수가 발생하여 커넥션 부족으로 인한 장애가 발생할 수 있다
커넥션 조회
TCP/IP 커넥션 획득
ID, PW 부가정보 전달
이후 , DB 내부 인증 + DB 세션 생성
커넥션 생성 완료
커넥션 반환
커넥션은 이와 같은 과정을 거치기에 복잡하고 시간이 많이 소비된다
이를 해결하기 위해 커넥션 풀 이라는 방법 도입, 커넥션을 미리 생성해두고 사용
커넥션 풀에 들어있는 커넥션들은 TCP/IP 연결이 되어있는 상태이기에 즉시 SQL을 DB에 전달 가능
커넥션을 사용하고 나면 종료하는게 아닌 풀에 반환!!
스프링 부트 2.0 부터는 기본 커넥션 풀로 hikariCP 를 제공 (오픈소스)
데이터베이스에서 트랜잭션은 하나의 거래를 안전하게 처리하도록 보장해주는 것을 뜻함
모든 작업이 정상적으로 처리되어 DB에 반영되면 커밋
실패해서 거래 이전으로 돌리는 것을 롤백 이라 한다
클라이언트와 DB가 커넥션을 맺을 떄 내부에 DB 세션을 만든다. 이후 해당 커넥션을 통한 모든 요청은 이 세션을 통해 실행된다
자동 커밋 모드에서 수동 커밋 모드로 전환 하는 것을 트랜잭션을 시작
한다고 표현한다고 함
애플리케이션 구조를 Controller - Service - Repository 로 나눈다면
이때 서비스 계층은 최대한 순수한 자바 코드로 작성해야 추후 UI 단이나 DB 단에서 변경이 일어나도 코드 수정 없이 유지가 될 수 있다
MemberServiceV2
코드에서는 트랜잭션을 서비스 단에서 시작해야 함으로 트랜잭션을 서비스 계층에서 시작했는데, JDBC 기술에 의존하게 되었다
인터페이스 PlatformTransactionManager (트랜잭션 매니저)
트랜잭션 매니저는 추상화 기능도 제공하지만, 동기화 기능도 제공한다, 이전에 파라미터로 넘기던걸 트랜잭션 동기화 매니저를 통해 사용
트랜잭션 동기화 매니저: 내부에서 쓰레드 로컬을 사용하기 때문에, 멀티 쓰레드 환경에서 안전하게 커넥션 동기화 가능 (뒤에서 자세히 배운다)
서비스 계층에서 트랜잭션 매니저.getTransaction 을 통해 트랜잭션 시작
트랜잭션 매니저가 내부에서 DataSource 를 통해 커넥션 만들어
수동 커밋 모드로 만든 커넥션을 트랜잭션 동기화 매니저에 보관
리포지토리는 보관된 커넥션을 사용 (파라미터로 전달 안해도 됨)
DataSourceUtils.getConnection
를 통해 보관된 커넥션을 가져오고
획득한 커넥션을 통해 SQL을 DB에 전달
처리 후 트랜잭션을 종료하기 위해 동기화 된 커넥션을 동기화 매니저에서 획득한다
커밋이나 롤백을 진행
트랜잭션 동기화 매니저를 정리하고, con.close 로 커넥션을 종료한다
DataSourceUtils.getConnection
를 통해 보관된 커넥션을 가져오고
DataSourceUtils.releaseConnection
로 트랜잭션 유지를 위해 커넥션을 닫지 않고 유지한다
만약 동기화 매니저가 관리하는 커넥션이 없을 경우에 커넥션을 닫는다
private final PlatformTransactionManager transactionManager
를 통해 트랜잭션 매니저를 주입 받는다.