SQL

JDBC vs SQL Mapper vs ORM

dddzr 2024. 9. 25. 23:22

JDBC, SQL Mapper, ORM은 모두 데이터베이스와 애플리케이션 간의 상호작용을 위해 사용되는 기술들이지만, 각기 다른 추상화 수준과 개발 방식이 적용됩니다. 간단한 코드 예시와 함께 이 세 가지의 차이점을 비교해보겠습니다.

1. JDBC (Java Database Connectivity)

특징

  • 직접적인 SQL 사용: JDBC는 SQL 쿼리를 직접 작성하여 데이터베이스와 통신하는 방식입니다.
  • 낮은 추상화 수준: 데이터베이스와의 상호작용을 상세하게 제어할 수 있으며, 데이터베이스 특화된 기능을 쉽게 사용할 수 있습니다.

장점

  • 제어력: 모든 SQL 쿼리와 연결 관리를 세밀하게 제어할 수 있습니다.
  • 성능 최적화: 성능에 민감한 작업에서 SQL 쿼리를 최적화하기 쉽습니다.

단점

  • 반복 코드: 자주 사용하는 코드(예: 연결, 자원 해제 등)가 반복될 수 있습니다.
  • 유지보수 어려움: SQL과 자바 코드가 밀접하게 결합되어 유지보수가 어려워질 수 있습니다.

예시 코드 (JDBC)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JDBCExample {
    public static void main(String[] args) {
        // DB 연결을 위한 URL, 사용자 이름, 비밀번호를 설정합니다.
        String url = "jdbc:mysql://localhost:3306/mydatabase";
        String user = "username";
        String password = "password";

        // 데이터베이스 연결을 시도하고, try-with-resources 문법을 사용해 자원 관리를 자동으로 처리합니다.
        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            
            // SQL 쿼리문을 작성합니다. 여기서는 ID가 1인 사용자를 조회합니다.
            String sql = "SELECT * FROM users WHERE id = ?";
            
            // PreparedStatement를 생성하고, SQL 쿼리의 인자에 값을 바인딩합니다.
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setInt(1, 1);  // 첫 번째 '?'에 1이라는 값을 설정 (ID 값)

                // 쿼리를 실행하고 결과(ResultSet)를 가져옵니다.
                try (ResultSet rs = stmt.executeQuery()) {
                    // 결과가 있을 때까지 반복하면서 데이터를 출력합니다.
                    while (rs.next()) {
                        System.out.println("User ID: " + rs.getInt("id"));
                        System.out.println("User Name: " + rs.getString("name"));
                    }
                }
            }
        } catch (Exception e) {
            // 예외가 발생한 경우 예외 스택 트레이스를 출력합니다.
            e.printStackTrace();
        }
    }
}

 

2. SQL Mapper (예: MyBatis)

특징

  • SQL과 객체 매핑: SQL 쿼리를 직접 작성하면서 객체와 데이터를 매핑할 수 있는 프레임워크입니다.
  • 중간 추상화 수준: SQL은 직접 작성하지만, 매핑과 트랜잭션 관리는 자동으로 처리됩니다.

장점

  • SQL에 대한 유연성: 복잡한 SQL 쿼리를 쉽게 작성할 수 있습니다.
  • 자동 매핑: SQL 쿼리 결과를 객체에 자동으로 매핑해줍니다.

단점

  • SQL 유지보수: SQL을 직접 작성해야 하므로, SQL이 복잡해지면 유지보수가 어려워질 수 있습니다.
  • 설정: XML 또는 애노테이션을 사용해 SQL과 매핑을 정의해야 합니다.

 

예시 코드 (MyBatis)

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
import org.apache.ibatis.io.Resources;

public class SQLMapperExample {
    public static void main(String[] args) {
        try {
            // MyBatis 설정 파일을 읽어 SqlSessionFactory를 생성합니다.
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            
            // SqlSession을 열고 데이터베이스와 상호작용을 시작합니다.
            try (SqlSession session = sqlSessionFactory.openSession()) {
                
                // SQL 쿼리와 매핑된 Java 메서드를 호출하여 데이터를 조회합니다.
                // "UserMapper.selectUser"는 MyBatis XML 파일에 정의된 매퍼로, ID가 1인 사용자를 조회합니다.
                User user = session.selectOne("UserMapper.selectUser", 1);
                
                // 조회된 사용자의 정보를 출력합니다.
                System.out.println("User ID: " + user.getId());
                System.out.println("User Name: " + user.getName());
            }
        } catch (Exception e) {
            // 예외가 발생한 경우 예외 스택 트레이스를 출력합니다.
            e.printStackTrace();
        }
    }
}

* Spring에서는 SqlSession 직접 사용 대신 자동으로 매핑된 Mapper 인터페이스를 주입받아 사용.

3. ORM (예: JPA/Hibernate)

특징

  • 객체-관계 매핑: 데이터베이스 테이블과 자바 객체를 매핑하여 SQL을 작성하지 않고도 데이터베이스와 상호작용할 수 있습니다.
  • 높은 추상화 수준: 데이터베이스와의 상호작용을 고수준으로 추상화하며, SQL은 자동으로 생성됩니다.

장점

  • 객체 지향적 접근: 코드가 객체 지향적으로 유지되며, 유지보수와 확장이 용이합니다.
  • 표준화: JPA는 자바 표준이며 여러 구현체(Hibernate, EclipseLink 등)가 있어 이식성이 높습니다.

단점

  • 복잡한 쿼리: 복잡한 쿼리 작성이 불편할 수 있으며 성능 최적화가 어려울 수 있습니다.
    • createQuery() / createNamedQuery() 같은 JPQL을 사용하여 복잡한 조회 쿼리를 실행할 수 있습니다.
    • 예: em.createQuery("SELECT u FROM User u WHERE u.name = :name")
  • 학습 곡선: JPA/Hibernate의 동작 방식과 매핑을 이해하는 데 시간이 걸릴 수 있습니다.
    • find(), persist(), merge(), remove()  등과 같은 JPA 또는 ORM 프레임워크에서 제공하는 주요 함수들을 알고 있어야 합니다.

 

예시 코드 (JPA/Hibernate)

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class ORMExample {
    public static void main(String[] args) {
        // EntityManagerFactory를 생성하여 JPA와 데이터베이스 간의 상호작용을 시작합니다.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit");
        
        // EntityManager는 데이터베이스와의 상호작용을 담당합니다.
        EntityManager em = emf.createEntityManager();

        // 데이터베이스 트랜잭션을 시작합니다.
        em.getTransaction().begin();
        
        // ID가 1인 사용자를 조회합니다. find() 메서드를 사용해 엔티티(User)를 가져옵니다.
        User user = em.find(User.class, 1);
        
        // 조회된 사용자의 정보를 출력합니다.
        System.out.println("User ID: " + user.getId());
        System.out.println("User Name: " + user.getName());
        
        // 트랜잭션을 커밋하여 데이터베이스 변경 사항을 확정합니다.
        em.getTransaction().commit();

        // EntityManager와 EntityManagerFactory를 닫아 자원을 해제합니다.
        em.close();
        emf.close();
    }
}


비교

  JDBC SQL Mapper (MyBatis) ORM (JPA/Hibernate)
추상화 수준 낮음 중간 높음
SQL 작성 직접 작성 직접 작성 자동 생성 (필요 시 직접 작성 가능)
유연성 매우 높음 높음 낮음 (쿼리 자동화)
생산성 낮음 (반복 코드) 중간 (매핑 자동화) 높음 (자동화)
성능 최적화 매우 용이 용이 어려울 수 있음
유지보수성 어려울 수 있음 중간 높음
  • JDBC는 최대한의 제어력과 유연성을 제공하지만, 반복적이고 복잡한 코드를 작성해야 합니다.
  • SQL Mapper (MyBatis)는 SQL 작성의 유연성을 유지하면서도 객체와 SQL을 쉽게 매핑해줍니다.
  • ORM (JPA/Hibernate)는 객체 지향적 프로그래밍에 집중할 수 있게 해주며, 데이터베이스 상호작용을 고도로 추상화합니다.