애플리케이션을 개발할 때 중요한 데이터는 대부분 데이터베이스에 보관한다.
그런데 데이터베이스마다 커넥션을 연결하는 방법, SQL을 전달하는 방법, 결과를 응답받는 방법이 모두 다르다.(관계형 데이터 베이스에는 수십개가 있음)
따라서 데이터베이스를 다른 종류의 데이터베이스로 변경하면 서버에 개발된 데이터베이스 사용 코드를 대부분 변경해야한다는 문제가 있다.
이런 문제를 해결하기 위해 JDBC라는 자바 표준이 등장하였다.
JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다.
JDBC는 데이터베이스에서 자료를 쿼리하거나 업데이트하는 방법을 제공한다. - 위키백과
대표적으로 다음 3가지 기능을 표준 인터페이스로 정의해서 제공한다.
이 JDBC 인터페이스를 각각의 DB 벤더(회사)에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공하는데, 이것을 JDBC 드라이버라 한다.

JDBC는 1997년에 출시될 정도로 오래된 기술이고, 사용하는 방법도 복잡하다. 그래서 최근에는 JDBC를 직접 사용하기 보다는 JDBC를 편리하게 사용하는 다양한 기술이 존재한다. 대표적으로 SQL Mapper와 ORM 기술로 나눌 수 있다.
SQL Mapper
장점: JDBC를 편리하게 사용하도록 도와준다.
SQL 응답 결과를 객체로 편리하게 변환해준다.
JDBC의 반복 코드를 제거해준다.
단점: 개발자가 SQL을 직접 작성해야한다.
대표 기술: 스프링 JdbcTemplate, MyBatis

ORM 기술
대표 기술: JPA, 하이버네이트, 이클립스링크

위의 그림과 같이 커넥션을 새로 만드는 것은 과정도 복잡하고 시간도 많이 소모되는 일이다.
이러한 문제를 해결하는 아이디어가 바로 커넥션을 미리 생성해두고 사용하는 커넥션 풀(커넥션을 관리하는 풀)이다.
애플리케이션을 시작하는 시점에 커넥션 풀은 필요한 만큼 커넥션을 미리 확보해서 풀에 보관한다(기본값 보통 10개)
커넥션을 얻는 방법은 JDBC의 DriverManager를 직접 사용하거나 커넥션 풀을 사용하는 등 다양한 방법이 있다.
각각의 사용법이 조금씩 다르기에 자바에서는 javax.sql.DataSource라는 인터페이스를 제공한다.
즉, DataSource는 커넥션을 획득하는 방법을 추상화하는 인터페이스이다.
데이터를 저장할 때 단순히 파일에 저장해도 되는데, 데이터베이스에 저장하는 이유는 여러가지 이유가 있지만, 가장 대표적인 이유는 바로 데이터베이스는 트랜잭션이라는 개념을 지원하기 때문이다.
트랜잭션(Transaction 이하 트랜잭션)이란, 데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다.
트랜잭션은 ACID라 하는 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 보장해야 한다.
원자성: 트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공 하거나 모두 실패해야 한다.
일관성: 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다.
격리성: 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다.
지속성: 트랜잭션을 성공적으로 끝내면 그 결과가 항상 기록되어야 한다. 중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용해서 성공한 트랜잭션 내용을 복구해야 한다.
세션1이 트랜잭션을 시작하고 데이터를 수정하는 동안 아직 커밋을 수행하지 않았는데, 세션2에서 동시에 같은 데이터를 수정하게 되면 여러가지 문제가 발생한다.(트랜잭션의 원자성이 깨짐)
여기에 더해서 세션1이 중간에 롤백을 하게 되면 세션2는 잘못된 데이터를 수정하는 문제가 발생한다.
이런 문제를 방지하려면, 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안에는 커밋이나 롤백 전까지 다른 세션에서 해당 데이터를 수정할 수 없게 막아야 한다.
1개의 세션만이 DB의 데이터에 접근이 가능한 것으로 데이터베이스는 여러 사용자들이 같은 데이터를 동시에 접근하는 상황에서, 데이터의 무결성과 일관성을 지키기 위해 락을 사용한다.
JDBC 구현 기술이 서비스 계층에 누수되는 문제
트랜잭션을 적용하기 위해 JDBC 구현 기술이 서비스 계층에 누수되었다.
서비스 계층은 순수해야 한다. -> 구현 기술을 변경해도 서비스 계층 코드는 최대한 유지할 수 있어야 한다. (변화에 대응)
서비스 계층은 특정 기술에 종속되지 않아야 한다.
트랜잭션 동기화 문제
같은 트랜잭션을 유지하기 위해 커넥션을 파라미터로 넘겨야 한다.
트랜잭션 적용 반복 문제
트랜잭션 적용 코드를 보면 반복이 많다.
커넥션을 열고, PreparedStatement 를 사용하고, 결과를 매핑하고... 실행하고, 커넥션과 리소스를 정리해야 한다.
현재 서비스 계층은 트랜잭션을 사용하기 위해서 JDBC 기술에 의존하고 있다. 향후 JDBC에서 JPA 같은 다른 데이터 접근 기술로 변경하면, 서비스 계층의 트랜잭션 관련 코드도 모두 함께 수정해야 한다.

서비스는 특정 트랜잭션 기술에 직접 의존하는 것이 아니라, TxManager 라는 추상화된 인터페이스에 의존한다. 이제 원하는 구현체를 DI를 통해서 주입하면 된다.
클라이언트인 서비스는 인터페이스에 의존하고 DI를 사용한 덕분에 OCP원칙을 지키게 되었다.
스프링이 제공하는 트랜잭션 매니저는 크게 2가지 역할을 한다.
트랜잭션 추상화(앞서 설명)
리소스 동기화

스프링은 트랜잭션 동기화 매니저를 제공한다. 이것은 쓰레드 로컬( ThreadLocal )을 사용해서 커넥션을 동기화해준다. 트랜잭션 매니저는 내부에서 이 트랜잭션 동기화 매니저를 사용한다.
커넥션이 필요하면 트랜잭션 동기화 매니저를 통해 커넥션을 획득하면 된다. 따라서 파라미터로 커넥션을 전달하지 않아도 된다.
템플릿 콜백 패턴을 활용하면 코드 반복 문제를 깔끔하게 해결할 수 있다.
템플릿 콜백 패턴을 적용하려면 템플릿을 제공하는 클래스를 작성해야 하는데, 스프링은 TransactionTemplate 라는 템플릿 클래스를 제공한다.
트랜잭션 템플릿의 기본 동작은 다음과 같다.
스프링 AOP를 통해 프록시를 도입
프록시 도입 전: 서비스에 비즈니스 로직과 트랜잭션 처리 로직이 함께 섞여있다.
프록시 도입 후: 트랜잭션 프록시가 트랜잭션 처리 로직을 모두 가져간다. 그리고 트랜잭션을 시작한 후에 실제 서비스를 대신 호출한다. 트랜잭션 프록시 덕분에 서비스 계층에는 순수한 비즈니즈 로직만 남길 수 있다.
개발자는 트랜잭션 처리가 필요한 곳에 @Transactional 애노테이션만 붙여주면 된다. 스프링의 트랜잭 션 AOP는 이 애노테이션을 인식해서 트랜잭션 프록시를 적용해준다.
@Transactional 애노테이션은 메서드에 붙여도 되고, 클래스에 붙여도 된다. 클래스에 붙이면 외부에서 호출 가능한 public 메서드가 AOP 적용 대상이 된다.
프록시 도입 후 전체 과정

트랜잭션은 커넥션에 con.setAutocommit(false)를 지정하면서 시작한다. 같은 트랜잭션을 유지하려면 같은 데이터베이스 커넥션을 사용해야 한다. 이것을 위해 스프링 내부에서는 트랜잭션 동기화 매니저가 사용된다.
JdbcTemplate 을 포함한 대부분의 데이터 접근 기술들은 트랜잭션을 유지하기 위해 내부에서 트랜잭션 동기화 매니저를 통해 리소스(커넥션)를 동기화 한다.
AOP를 적용하면 스프링은 대상 객체 대신에 프록시를 스프링 빈으로 등록한다. 따라서 스프링은 의존관계 주입시에 항상 실제 객체 대신에 프록시 객체를 주입한다.
프록시 객체가 주입되기 때문에 대상 객체를 직접 호출하는 문제는 일반적으로 발생하지 않는다. 하지만 대상 객체의 내부에서 메서드 호출이 발생하면 프록시를 거치지 않고 대상 객체를 직접 호출하는 문제가 발생한다.
이렇게 되면 @Transactional 이 있어도 트랜잭션이 적용되지 않는다는 것을 꼭 기억해야 한다.

예외 발생시 스프링 트랜잭션 AOP는 예외의 종류에 따라 트랜잭션을 커밋하거나 롤백한다.
트랜잭션을 각각 사용하는 것이 아니라, 트랜잭션이 이미 진행중인데, 여기에 추가로 트랜잭션을 수행하면 어떻게 될까?
기존 트랜잭션과 별도의 트랜잭션을 진행해야 할까? 아니면 기존 트랜잭션을 그대로 이어 받아서 트랜잭션을 수행해야 할까?
이런 경우 어떻게 동작할지 결정하는 것을 트랜잭션 전파(propagation)라 한다.

스프링은 이해를 돕기 위해 논리 트랜잭션과 물리 트랜잭션이라는 개념을 나눈다.
논리 트랜잭션들은 하나의 물리 트랜잭션으로 묶인다.
물리 트랜잭션은 우리가 이해하는 실제 데이터베이스에 적용되는 트랜잭션을 뜻한다. 실제 커넥션을 통해서 트랜잭션을 시작( setAutoCommit(false)) 하고, 실제 커넥션을 통해서 커밋, 롤백하는 단위이다.
논리 트랜잭션은 트랜잭션 매니저를 통해 트랜잭션을 사용하는 단위이다.
이러한 논리 트랜잭션 개념은 트랜잭션이 진행되는 중에 내부에 추가로 트랜잭션을 사용하는 경우에 나타난다.
단순히 트랜잭션이 하나인 경우 둘을 구분하지는 않는다. (더 정확히는 REQUIRED 전파 옵션을 사용하는 경우에 나타나고, 이 옵션은 뒤에서 설명한다.)
원칙
모든 논리 트랜잭션이 커밋되어야 물리 트랜잭션이 커밋된다.
하나의 논리 트랜잭션이라도 롤백되면 물리 트랜잭션은 롤백된다.

핵심 정리
여기서 핵심은 트랜잭션 매니저에 커밋을 호출한다고해서 항상 실제 커넥션에 물리 커밋이 발생하지는 않는다는 점이다.
신규 트랜잭션인 경우에만 실제 커넥션을 사용해서 물리 커밋과 롤백을 수행한다. 신규 트랜잭션이 아니면 실제 물리 커넥션을 사용하지 않는다.
이렇게 트랜잭션이 내부에서 추가로 사용되면 트랜잭션 매니저에 커밋하는 것이 항상 물리 커밋으로 이어지지 않는다. 그래서 이 경우 논리 트랜잭션과 물리 트랜잭션을 나누게 된다.
또는 외부 트랜잭션과 내부 트랜잭션으로 나누어 설명하기도 한다.
REQUIRES_NEW는 외부 트랜잭션과 내부 트랜잭션을 완전히 분리해서 각각 별도의 물리 트랜잭션을 사용하는 방법이다. 그래서 커밋과 롤백도 각각 별도로 이루어지게 된다.

이 방법은 내부 트랜잭션에 문제가 발생해서 롤백해도, 외부 트랜잭션에는 영향을 주지 않는다. 반대로 외부 트랜잭션에 문제가 발생해도 내부 트랜잭션에 영향을 주지 않는다.
적용 데이터 접근 기술
크게 2가지 분류를 하면
SQLMapper
JdbcTemplate
MyBatis
ORM 관련 기술
JPA, Hibernate
스프링 데이터 JPA
Querydsl
로 구분할 수 있는데 하나씩 살펴보도록 하겠다.
장점
1.설정의 편리함
JdbcTemplate은 spring-jdbc 라이브러리에 포함되어 있는데, 이 라이브러리는 스프링으로 JDBC를 사용할 때 기본으로 사용되는 라이브러리이다. 그리고 별도의 복잡한 설정 없이 바로 사용할 수 있다.
2.반복 문제 해결
JdbcTemplate은 템플릿 콜백 패턴을 사용해서, JDBC를 직접 사용할 때 발생하는 대부분의 반복 작업을 대신 처리해준다.
개발자는 SQL을 작성하고, 전달할 파리미터를 정의하고, 응답 값을 매핑하기만 하면 된다.
단점
동적 SQL을 해결하기 어렵다.
주요 기능
JdbcTemplate
순서 기반 파라미터 바인딩을 지원한다.
NamedParameterJdbcTemplate
이름 기반 파라미터 바인딩을 지원한다.(권장)
SimpleJdbcInsert
INSERT SQL을 편리하게 사용할 수 있다.
SimpleJdbcCall
스토어드 프로시저를 편리하게 호출할 수 있다
동적 쿼리 문제를 해결하면서 동시에 SQL도 편리하게 작성할 수 있게 도와주는 기술이 바로 MyBatis 이다.
MyBatis는 앞서 설명한 JdbcTemplate보다 더 많은 기능을 제공하는 SQL Mapper 이다.
기본적으로 JdbcTemplate이 제공하는 대부분의 기능을 제공한다.
JdbcTemplate과 비교해서 MyBatis의 가장 매력적인 점은 SQL을 XML에 편리하게 작성할 수 있고 또 동적 쿼리를 매우 편리하게 작성할 수 있다는 점이다.
설정의 장단점
JdbcTemplate은 스프링에 내장된 기능이고, 별도의 설정없이 사용할 수 있다는 장점이 있다. 반면에 MyBatis는 약간의 설정이 필요하다.
build.gradle 에 다음 의존 관계를 추가해야 한다.
//MyBatis 추가 implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
다음과 같은 라이브러리가 추가된다.

-매퍼 구현체 덕분에 마이바티스를 스프링에 편리하게 통합해서 사용할 수 있다.
-매퍼 구현체를 사용하면 스프링 예외 추상화도 함께 적용된다.
-마이바티스 스프링 연동 모듈이 많은 부분을 자동으로 설정해주는데, 데이터베이스 커넥션, 트랜잭션과 관련된 기능도 마이바티스와 함께 연동하고, 동기화해준다.
JPA부터는 양도 방대하고 매우 중요하기에 다음에 자세히 살펴보도록 하겠다.