Back-end
내에서 Persistence
는 프로그램이 실행되는 동안 만든 데이터를 프로그램이 종료되어도, 남아있을 수 있도록 이를 영구적으로 저장 (영속) 하는 것을 의미한다. 즉, 프로그램이 생성한 데이터를 저장을 할 공간이나 도구에게 어떻게 전달 하여 데이터를 영구적으로 보관 하느냐가 중요했다.
저장을 위한 도구로는 파일 시스템, 객체 스토리지, 데이터베이스 등이 존재하며, 그 중 개발에서 많이 사용되는 저장 도구는 관계형 DB
이다. 그리고 서버와 DB
와의 연결과정을 담당하는 persistence
기술들은 지금까지도 개발 환경의 필수 스택으로 자리매김하고 있다.
Java Spring
진영에서 대표적으로 사용되는 persistence
기술의 등장배경과 특징을 알아보자.
JDBC
는 Java DataBase Connectivity
의 약자로, Java
언어가 데이터베이스에 접근하기 위한 표준 인터페이스이다.
JDBC
는 1997년에 등장했으며, JDBC
가 등장하게 된 배경에는 다음과 같은 측면들이 존재한다.
1990년대 후반은 웹의 상용화를 통해 웹으로 수익을 창출할 수 있다는 것이 확립된 시기이며 마이크로소프트의 Internet Explorer
와 넷스케이프의 브라우저 경쟁이 치열하게 이루어지며, 웹 기술의 발전과 보급이 가속화 되었다.
이 시기에는 다양한 관계형 DB
들이 나타난 시기이며, DB
제조사들이 각 DB
에 대한 고유의 접속 방법 및 API
를 가지고 있었다. 행여 여러 DB
를 사용하는 서비스이거나, 서비스의 DB
를 교체하는 상황에는 각 DB
에 대한 설정과 별도의 코드를 작성해야하는 번거로움을 초래했다.
이 시기 Java
진영에는 Servlet
이 등장하며, Java
를 통한 웹 어플리케이션 개발이 확산되던 시기였다. 정적 페이지를 통한 서비스 제공에서, 동적인 컨텐츠를 생성할 수 있다는 획기적인 특징 덕분에 웹 시장에서 Java
언어는 큰 인기를 누리던 시기였다.
이러한 과정들은 추후 Java
진영에서 Servlet, JDBC
등의 웹 개발에 필요한 기술을 한데 모아, 하나의 플랫폼으로 엮은 JavaEE
를 출시하는 결과를 가져오기도 했다.
JavaEE
:Java
를 사용하여 대규모 엔터프라이즈 환경에서 웹 어플리케이션을 개발하기 위한 표준 플랫폼
JDBC
가 강조했던 특징은 바로 DB
연결 시의 번거로움을 개선하는 것이다. JDBC
측에서는 DB
연결을 위한 인터페이스를 제공했고, 각 데이터베이스 제조사는 자신의 DB
에 맞는 구현체를 설계했는데, 해당 구현체들이 JDBC Driver
이다.
이로써 개발자는 JDBC Driver
만 바꾸는 과정만으로 기존의 코드를 그대로 유지하면서 별도의 설정없이 DB
를 교체하는 것이 가능했다.
JDBC
사용 방법은 크게 3가지로 나눌 수 있다.
DB
와의 연결을 수행해야하는 영역statement
영역DB
쿼리 실행 이후 결과처리를 수행해야하는 영역public Optional<Member> findByName(String name) {
String sql = "select * from member where name = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
rs = pstmt.executeQuery();
if (rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
}
return Optional.empty();
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
SQL Mapper
는 객체와 데이터베이스 간의 매핑을 자동으로 처리하고, 반복적이고 복잡한 JDBC
코드 작성을 최소화하여 개발자가 JDBC API
대비 보다 간편하게 서버와 DB
가 상호작용할 수 있도록 지원한다.
JDBC
를 통해 DB
와의 연결 및 교체가 간편해졌으나 메서드 설계마다 DB 커넥션, 쿼리 실행, 결과 처리
등을 반복하여 작성해야 했다. 더불어, 1개의 메서드에 Java
, 쿼리
, DB 연결
에 대한 코드가 모두 존재하기 때문에 코드의 재사용성, 가독성이 좋지 않다는 단점을 가지고 있었다.
이러한 부분을 개선하기 위해, JDBC
수행하는 일련의 공통사항을 추상화하는 작업이 진행되었고, 이 과정에서 SQL Mapper
가 등장하게 된다.
Spring Framework
에서 공식적으로 제공한 JDBC
기반의 데이터 엑세스 기술, 기존의 JDBC
의 기능을 유지하면서도, 공통사항에 대한 추상화를 통해 기존의 반복적이고 번거로운 JDBC
작업을 간소화했다.
Spring JDBC
가 개선한 주요 기능은 다음과 같다.
DataSource 추상화 : properties 파일을 통해, DB
에 대한 연결 설정을 통해, 구현 코드와 설정 코드의 영역을 분리시킬 수 있다. Spring JDBC
는 서버 실행 시 해당 DB
설정을 기반으로 JDBC Templete
을 생성하고, 구현 코드에서는 JDBC Template
을 활용하여 DB
엑세스가 가능해진다.
트랜잭션 관리 : 기존에는 트랜잭션 대한 커밋과 롤백을 직접적으로 설정해야 했다면, Spring JDBC
에서는 트랜잭션에 대한 기본 설정을 자동으로 관리한다.
예외 처리 공통 사항 설계 : JDBC
에서 발생할 수 있는 예외를 일관되게 처리하여, 개발자의 예외 관리를 업무를 간소화시켰다.
DTO
매핑 : 쿼리의 결과를 자동으로 DTO
에 맞게 매핑하여 객체 결과를 가져온다.
MyBatis
의 경우, 기존 JDBC
코드에서 SQL
에 대한 영역을 분리시키는 것에 주안점을 두었다. 쿼리에 대한 코드를 XML
로 옮기는 것으로, 업무의 분업화를 통해 코드의 유지보수성과 가독성을 높였다.
@Mapper // 등록
// 작성
public interface UserMapper {
User getUserById(int id);
void insertUser(User user);
...
...
}
<!-- user_mapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
<select id="getUserById" parameterType="int" resultType="com.example.model.User">
SELECT * FROM users WHERE id = #{id}
</select>
<insert id="insertUser" parameterType="com.example.model.User">
INSERT INTO users (name, email) VALUES (#{name}, #{email})
</insert>
...
...
</mapper>
Object-Relational Mapping
의 약자로, 객체와 관계형 DB
간의 상호작용을 도와주는 기술이다. ORM
의 경우에는, 객체와 관계형 DB
의 불일치를 해결하는데 중점을 두었다.
객체의 경우 참조 형태를 통해 객체 내부에 또다른 객체를 담을 수 있으나, DB
의 경우 외래키를 통해 테이블 간의 연관성을 설계한다. 더불어, 객체는 리스트, 배열을 통해 다수의 데이터를 하나의 꾸러미에 담는 것이 가능하지만 DB
의 경우 이러한 자료구조가 존재하지 않으며, 하나의 행에 다수의 데이터를 담는 것도 불가능하다.
객체 지향 프로그래밍이 등장하면서 복잡한 개발 기술을 현실의 문제를 해결할 수 있도록 녹여내었지만, 객체 결과를 DB
에 저장하는 과정에서 객체와 DB
간의 본질적인 차이로 인해, 객체 지향적이지 못한 코드를 작성해야하는 문제가 발생했다. ORM
은 이러한 객체와 관계형 DB
의 차이를 해결하여, 객체 지향적인 코드를 유지하면서도 관계형 DB
에 접근하여 persistence
를 보장할 수 있는 기술이다.
Java Persistence API
의 약자로, Java
에서 객체 지향 프로그래밍과 관계형 DB
간의 상호작용을 지원한다.
주요 특징으로는 다음과 같다.
Persistence Context : JPA
는 영속성 컨텍스트를 통해 객체와 DB
간의 불일치를 해결한다. DB
에 반영되는 객체를 Entity
라 칭하며 영속성 컨텍스트를 통해 Entity
를 관리하게 된다. Entity
를 관리하는 Entity Manager
는 Entity
객체 상태를 추적하여, 변경 사항을 데이터베이스에 동기화하는 역할을 담당한다.
JPQL : JPA
는 객체를 대상으로 하는 쿼리 작성을 지원한다. SQL
쿼리와 유사하면서도 테이블이 아닌 객체에 집중한다.
성능 최적화 : 트랜잭션 내부의 1차 캐싱, 지연 로딩, 배치 최적화, fetch join
등 DB
통신 시의 성능 향상을 지원해준다.
Spring Framework
에서 제공하는 모듈 중 하나로, JPA
에서 자주 일어나는 반복적인 작업들을 추상화하여, 생산성을 향상시킨 기술이다.
이러한 점은 위의
Spring JDBC
가 나타난 등장배경과 유사하다.
Spring Data JPA
의 주요 특징은 다음과 같다.
Repository Interface
: Spring Data JPA
의 핵심 요소로, 인터페이스만 설계하여도 Spring
측에서 서버 실행 시 해당 인터페이스에 대한 구현체를 자동으로 생성한다. 생성된 구현체에는 이미 Repostiory Interface
를 통해 save()
, findById(Long id)
등, JPA
개발시 공통적으로 많이 구현하는 메서드들을, 적용한 엔티티에 맞게 자동으로 생성하기 때문에, ORM
에 대한 개발자의 업무를 상당 수 줄일 수 있다.
Query Method
: 메서드 구현 시 엔티티 필드를 포함한 특정 규칙에 따라 메서드 이름을 작성하면, Spring Data JPA
가 자동으로 쿼리를 생성한다.
예를 들어 lastName
필드를 가진 User
엔티티가 존재할 때, findByLastName(String lastName)
라 메서드 이름을 Repository Interface
에 부여하는 경우, 헤당 메서드 호출 시 실제 lastName
이 일치하는 User
데이터를 조회하는 쿼리가 수행된다.
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastName(String lastName);
}
참고
[10분 테코톡] 🧘♂️코즈의 JDBC, SQLMAPPER, ORM
[Spring] Spring JdbcTemplate 가이드 (공식문서, Baeldung)
Spring JDBC의 정의와 특징
[Spring + JPA] Spring Data JPA 란? (1)
[JPA] JPA란? Spring Data JPA로 간단 예제 프로젝트 구현
[Spring JPA] JPA 란?
Hibernate – 11th Hour