[Spring boot] JDBC와 Spring JDBC 그리고 MyBatis

지난 포스트에서 MVC 패턴과 Spring Data Rest를 이용해 간단한 REST API 서버를 개발해보는 시간을 가졌었는데요. 그런데, 우리가 여기에서 DB와 연동하기 위해 사용했던 디펜던시가 있었죠. 바로 Spring Data JPA였습니다.

그런데, 기존의 Spring을 사용했던 분이시나, STS 내지 전자정부프레임워크를 사용하셨던 분들은 JPA보다는 MyBatis에 익숙하실 것입니다. 그러나 MyBatis는 기존의 Spring 처럼 의존성 주입을 XML 파일을 이용해 진행하게 되고, 원하는 데이터를 가져오기 위해 메소드에 DB 쿼리를 질의하는 등의 방식을 이용해야 합니다.

이번 포스트에서는 Spring Application이 어떻게 DB와 연결하여 Spring Data JPA까지 오게 되었는지를 두 포스트로 나누어서 이야기를 해보고자 합니다.

 

 

JDBC

Java 계열에서 DB에 대한 이야기를 시작하자면, 이 녀석을 빼놓을 수 없죠. 기본적으로 Spring 프레임워크를 사용하기 전에, 일반 Java 언어에서 DB 연결을 위해 사용하는 것이 바로 JDBC입니다. JDBC란, Java DataBase Connectivity의 약자로 자바와 데이터베이스를 연결하기 위한 Java 표준 인터페이스를 말합니다. MySQL, PostgreSQL, SQL Server 등 다양한 DB 미들웨어의 드라이버를 제공하고, Java 표준이기 때문에 JVM 위에서 운영되는 애플리케이션 어디에서든지 사용할 수 있다는 장점이 있죠.

간단하게 JDBC가 동작하는 원리를 설명드리자면, 먼저 사용할 Database Driver를 선택해주고, 커넥션을 생성합니다. 그리고 처리해야 할 질의를 executeSQL에 넣어준 후, ResultSet으로 받는 경우가 보통의 JDBC를 이용하는 방법입니다.

그러나 커넥션을 종료할 때, close 함수를 Statement, Connection, ResultSet에 모두 하여야, 메모리 누수가 생기지 않고, 안전하게 종료할 수 있어 코드의 가독성이나 불편함이 존재하는 면이 있죠. 매번 실행할 때마다 결과 셋을 클래스로 묶어서 리팩토링 한다면, 그를 매번 종료해야 하는 번거로움이 생깁니다.

 

Spring JDBC

스프링 JDBC야 말로, 스프링에서 DB를 사용하기 위한 오리지날 디펜던시라고 할 수 있습니다. MyBatis처럼 XML을 이용해 의존성 주입을 한 후, 사용하는 방식입니다.

위에서 쌩 JDBC를 사용할 때, PrepareStatement, CreateStatement, ResultSet 등 자주 사용하는 객체와 코드들을 클래스화 하여 스프링 애플리케이션에서 보다 더 편하게 DB에 접근할 수 있는 인터페이스를 제공한다는 점이 있죠. 구체적으로 Spring JDBC가 제공해주는 역할은 아래와 같습니다.

  • Connection을 열고 닫기
  • Statement를 준비하고 닫기
  • Statement의 실행
  • ResultSet 반복 처리
  • 예외 처리 반환
  • Transaction 처리

잘 보면, 위에서 사용한 JDBC의 코드들을 자동으로 처리해주고, 개발자는 DataSource만 제공해주면, 위의 작업을 모두 알아서 처리해주는 아주 좋은 녀석이라는 거죠.

그런데, 한 가지 문제점이 있습니다. Spring 애플리케이션을 개발하다보면, 도메인 기반 디자인으로 설계를 하게 됩니다. 예를 들면, 회원 정보에 대한 부분은 Member 도메인을 설계하여, 그에 해당하는 Repository를 생성하고, 비즈니스 로직은 Service에서 처리하며, 클라이언트의 요청은 Controller에서 처리하는 MVC 패턴까지 겸하고 있죠. 이렇게 디자인 하다보니, Service와 DB를 연결해야 하는 라인이 필요했는데, 우리는 이를 DAO라고 이야기 합니다.

Data Access Layer

위 사진은 Spring JDBC의 Data Access Layer를 그린 모습입니다. JDBC Template에는 개발자가 설정한 DataSource가 담겨져 있고, 이를 통해 JDBC 커넥션을 생성하여 DB와 연결하는 형태로 진행됩니다.

JDBC에서 가장 일반화된 연결 팩토리인 DataSource는 인터페이스로 제공되는데, 이 팩토리는 DB와 관계된 Connection을 담고 있어, 의존성 주입을 통해 넘겨주는 것이 좋습니다. 왜냐하면, 클라이언트 요청에 Database Access가 언제든 생길 수 있다는 점을 고려해야 하기 때문입니다.

DataSource 인터페이스를 구현한 대표적인 클래스들은 아래와 같습니다.

  • BasicDataSource
  • PoolingDataSource
  • SingleConnectionDataSource
  • DriverManagerDataSource

따라서 Spring JDBC를 사용하기 위해 DB Connection을 가져오는 DataSource를 위의 소스 코드와 같이 Spring IoC 컨테이너에 공유 가능한 Bean으로 등록한 후, Spring JDBC에 주입하면 됩니다.

그런 뒤에 DAO 클래스를 구현하여, 사용할 메소드를 정의하고, 그에 해당하는 SQL 쿼리를 JDBCTemplate에 넣어주면, 위에서 사용했던 JDBC의 Statement, Connection 코드를 써주지 않고도 쉽게 가져올 수 있습니다.

 

 

MyBatis / iBatis

MyBatis는 Spring JDBC와 유사합니다. 의존성 주입을 XML로 진행하고, JDBC에 사용하는 순수 코드들 역시 모두 자동으로 작성해주죠.

다른 점이 있다면, MyBatis는 SqlSession을 열고 SQL 쿼리를 실행한다는 점입니다. SQL 쿼리를 동작하기 전에, 세션을 미리 열고, 실행할 때 동작시킨 다음, 종료가 되면 이를 Release 해야 하는 방식인 것이죠. 또 한가지는 Spring JDBC는 Java 코드에 직접 SQL 쿼리를 질의하고, 이를 함수화하여 사용하였지만 MyBatis는 XML에 SQL 쿼리를 질의하고, Java 코드에서 인터페이스를 만들어, Mapping 하는 형태로 코딩을 진행한다는 점입니다.

이것을 우리는 관심사의 분리라고 이야기 합니다. 비즈니스 로직은 비즈니스 로직에 DB 처리 로직은 DB에 걸맞게 넣겠다는 것이죠. 

Spring JDBC처럼 DataSource를 설정하지만 DataSource 인터페이스를 상속받은 클래스를 쓰지 않고, 자체적으로 제공하는 Environment를 사용합니다. 이는 Spring JDBC처럼 풀링을 지원합니다. 그리고, 각 도메인에 대해서 DB 처리 로직을 분리해야 하기 때문에 SQL 코드와 매핑되는 Mapper를 만들어주고, 이를 properties에 넣어줘야 합니다.

XML에서 SQL 코드를 질의할 때 이와 같이 구현하고, 이를 Java의 인터페이스에서 한 번 더 구현해주면, Java 코드에서 이를 불러와 처리를 하는 방식입니다.

XML이 아닌 인터페이스 내에서 어노테이션을 이용해 직접 SQL 쿼리를 정의할 수도 있습니다.

그러나 이게 끝이 아닙니다. 여기에서 Spring JDBC처럼 연결 커넥션을 만들어줘야 하는데, MyBatis에서는 SqlSession 클래스를 이용해 세션을 오픈하고, 이 작업이 끝나면 세션을 닫아줘야 합니다.

확실한 건, SQL 코드와 자바 코드를 분리시켜줌으로써 코드가 분리되어, 가독성이 좋고 유지보수가 편해짐을 알 수는 있지만, 세션을 오픈하고, 닫고 사용하는 것은 오히려 더 번거로운 일인 것 같습니다.

사실 SqlSession 이외에도 SqlSessionFactoryBuilder나 SqlSessionFactory도 존재하는데, SqlSession 클래스만 Release 작업을 해줘야 하고, Factory의 경우, 애플리케이션이 실행되는 동안은 계속 남기 때문에 싱글톤 패턴처럼 쓸 수 있는 점 등 다양한 장단점이 존재하기 때문에 이 부분에 대해서도 개발자가 신경써서 코딩해야 한다는 점, SqlSession은 인스턴스가 공유되지 않고 Thread-safe하지 못해 요청하는 순간만 사용하도록 하면 되지만, 이렇게 될 경우, 요청마다 시스템 자원을 가져다 쓰기 때문에 그렇게 좋은 선택은 아닌 것 같네요.

 

마치며...

이번 포스트에서는 JDBC ~ MyBatis까지를 다뤄봤습니다. 우리가 지난 포스트에서 다룬 Spring Data JPA는 Session이나 Connection 등은 전혀 신경쓰지 않고, 프로그래밍 하였는데, 실제로 Java에서 DB와 연결하는 작업은 꽤 번거로운 작업이었다는 걸 알았습니다.

이를 개선하고, 관심점 분리 등 다양한 고민을 통해 결국 batis 구간까지 오게되었지만, 아직까지 아쉬운 점이 남아있는 것은 바로 관계형을 정의하기가 어렵다는 점입니다. 예를 들면, 게시판을 만든다고 가정하였을 때, 게시글과 댓글은 1:N 관계로 존재하는 녀석입니다. 그러나 애플리케이션에서 이를 1:N 관계로 정의할 수 있는 방법은 오직 SQL 쿼리로 질의하는 방법인데, 이 방법은 러닝 커브가 높고, 구현하기가 어렵죠.

이러한 점을 개선한 Hibernate, JPA, Spring Data JPA에 대해 다음 포스트에서 다뤄보도록 하겠습니다.

TAGS. ,
comments powered by Disqus

Tistory Comments 0