Spring

[Spring] RDBMS에서 ORM까지

부리부리부리부리 2023. 12. 12. 15:42

개요

RDBMS

 

관계형 데이터베이스(關係形 Database, Relational Database) 는 키(key)와 값(value)들의 간단한 관계를 테이블화 시킨 매우 간단한 원칙의 전산정보 데이터베이스이다. 1970년 에드거 F.커드 제안한 데이터 관계형 모델에 기초하는 디지털 데이터베이스이다. (출처 : 위키백과)

 

RDBMS의 대표적인 종류로 너무나도 익숙한 MySQL이 있다. Spring 프로젝트를 진행하면서 RDBMS와 통신하기 위해 JDBC API를 사용했다.

 

JDBC

JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다. JDBC는 데이터베이스에서 자료를 쿼리하거나 업데이트하는 방법을 제공한다. (출처 : 위키백과)

 

JDBC Driver라는 Middleware를 통해 Java와 Database를 연결할 수 있다. Oracle JDBC Driver, MYSQL JDBC Driver, Sybase JDBC Driver등이 제공된다.

 

https://velog.io/@codepark_kr

 

우선 JDBC는 표준 인터페이스를 사용하기 때문에 사용중이던 MySQL DB가 Oracle DB로 바뀌더라도 Driver만 교체하면 된다. 즉 여러 RDBMS에 대해 일관된 방식으로 데이터베이스에 접근할 수 있다.

 

하지만 위 그림에서 알 수 있듯 쿼리 한번을 실행하기 위해 쓰이는 코드가 너무나도 많고, 중복이 된다.

다음은 간단한 select문을 위해서 JDBC로 조회하는 코드이다.

 

Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;

try {
    // 데이터베이스에 연결
    connection = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);

    // 쿼리 실행
    String query = "SELECT id, name FROM users WHERE age > ?";
    preparedStatement = connection.prepareStatement(query);
    preparedStatement.setInt(1, 18);
    resultSet = preparedStatement.executeQuery();

    // 결과 처리
    while (resultSet.next()) {
        int userId = resultSet.getInt("id");
        String userName = resultSet.getString("name");
        System.out.println("User ID: " + userId + ", User Name: " + userName);
    }

} catch (SQLException e) {
    e.printStackTrace();
} finally {
    // 연결 및 리소스 해제
    try {
        if (resultSet != null) resultSet.close();
        if (preparedStatement != null) preparedStatement.close();
        if (connection != null) connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

 

간단한 select임에도 connection, preparedStatement, resultSet 객체 생성,리소스도 수동으로 해제해야하는 등, 개발자가 많은 작업을 해야하는데 코드가 중복되기까지 한다.

SQL Mapper

SQL Mapper는 Java Persistence Framework 중 하나이다. JDBC만 사용했을 때 중복된 코드가 많고 자원을 직접적으로 관리해줘야하는 불편함을 SQL Mapper를 통해 어느 정도 해소할 수 있게 되었다. MyBatis가 SQL Mapper의 종류이다.

귀여운 짹짹이

 

MyBatis는 SQL 쿼리들을 XML 파일에 작성하여 코드와 SQL을 분리하여 관리한다. JDBC만 사용하면 결과를 가져와서 객체의 인스턴스에 매핑하기 위한 많은 코드가 필요하겠지만, 마이바티스는 그 코드들을 작성하지 않아도 되게 해준다.

<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- User 엔티티와 관련된 SQL 쿼리 매핑 -->
<mapper namespace="com.example.mappers.UserMapper">

  <!-- 사용자 정보 조회 -->
  <select id="getUserById" parameterType="int" resultType="com.example.model.User">
    SELECT * FROM users WHERE id = #{id}
  </select>
  
    <!-- 동적 쿼리 - 사용자 검색 -->
  <select id="searchUsers" parameterType="com.example.model.User" resultType="com.example.model.User">
    SELECT * FROM users
    <where>
      <!-- 사용자 ID가 주어진 경우 -->
      <if test="id != null">
        AND id = #{id}
      </if>
      <!-- 사용자 이름이 주어진 경우 -->
      <if test="username != null and username != ''">
        AND username = #{username}
      </if>
      <!-- 이메일이 주어진 경우 -->
      <if test="email != null and email != ''">
        AND email = #{email}
      </if>
    </where>
  </select>

</mapper>

 

이런 식으로 따로 xml 파일을 만들어놓고 쿼리를 작성하며 <if>, <when> 등의 태그로 동적 쿼리를 작성 할 수 있다.

하지만 이렇게 SQL Mapper를 사용함에도 개발자가 불편함을 느낄 수 밖에 없는 근본적인 원인이 존재했다.

 

패러다임 불일치

패러다임 불일치(Paradigm Mismatch)란 두 가지 다른 프로그래밍 패러다임이나 모델 간에 발생하는 불일치를 나타낸다. 이는 서로 다른 방식으로 문제를 해결하거나 데이터를 모델링하는 데에 있어서 어려움을 의미하는데, 객체 지향 프로그래밍에서는 클래스와 객체를 중심으로 데이터를 모델링하고, 관계형 데이터베이스에서는 테이블과 관계를 중심으로 데이터를 저장한다. 이로 인해 객체의 상속, 다형성 등과 같은 개념들을 효과적으로 표현하기 어렵다. 

출처: 유튜브 테코톡 (https://www.youtube.com/watch?v=VTqqZSuSdOk&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH&index=66)

 

Object Relational Mapper (ORM)

https://hanamon.kr/orm%EC%9D%B4%EB%9E%80-nodejs-lib-sequelize-%EC%86%8C%EA%B0%9C/

 

Object-Relational Mapping은 객체-관계 매핑을 나타낸다. 이는 객체 지향 프로그래밍(OOP)과 RDBMS 간의 데이터를 변환하고 연결하는 프로그래밍 기술 또는 패러다임을 나타낸다. ORM을 통해 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 불일치를 해결한다.

장점

  1. 객체 지향적인 코드: ORM을 사용하면 객체 지향 언어에서 자연스럽게 사용되는 클래스와 객체를 활용하여 데이터베이스를 다룰 수 있다.
  2. 데이터베이스 독립성: ORM은 데이터베이스에 대한 접근을 추상화하므로 특정 데이터베이스에 의존하지 않고 여러 종류의 데이터베이스 시스템을 사용할 수 있다.
  3. 생산성: SQL 쿼리를 직접 작성하는 대신 ORM을 사용하면 개발 속도를 향상시킬 수 있다. 객체 지향 코드를 작성하고 데이터베이스 연동을 자동화함으로써 개발자는 비즈니스 로직에 집중할 수 있다.

단점

  1. 성능 손실: ORM은 객체와 데이터베이스 간의 매핑을 제공하기 위해 추가적인 오버헤드를 유발할 수 있다. 이는 데이터베이스 쿼리를 직접 작성하는 것보다 성능 손실을 초래할 수 있다.
  2. 복잡성: 복잡한 데이터 모델이나 복잡한 쿼리를 처리할 때 ORM은 복잡성을 증가시킬 수 있다.
  3. 진입 장벽: ORM을 사용하려면 ORM 프레임워크의 개념과 동작 방식을 이해해야 한다.

JPA, Hibernate

JPA(Java Persistence API)는 자바의 ORM 기술 표준으로 인터페이스의 모음이다. 이러한 JPA 표준 명세를 구현한 구현체가 바로 Hibernate이다.