SQL Mapper vs ORM (with JDBC)

한강섭·2025년 5월 6일
0
post-thumbnail

썸네일 출처

JDBC, SQL Mapper, ORM

JDBC의 단점을 해결하기 위한 SQL Mapper,
SQL로부터 벗어날 수 없는 문제점을 해결하기 위한 ORM


Persistence : 영속성
도메인 모델인 객체에 영속성을 부여하는 역할을 한다.


사진 출처

바로 이 Persistence Layer를 어떻게 구성할까?

JDBC만을 이용하여 만들기 VS Persistence Framework를 이용하는 방법


JDBC (Java Database Connectivity)

자바 애플리케이션에서 DBMS의 종류에 상관없이, 하나의 JDBC API를 이용해 DB 작업을 처리

Connection conn = DriverManager.getConnection(url,user,password);
String sql = "SELECT * FROM emp WHERE empno = ?";
PreparedStatement pstmt = conn.prepareStatement(sql); //prepared 로 sql인젝션 방지! 
pstmt.setInt(1, empNo);
ResultSet rs = pstmt.executeQuery(); // SELECT 문
// int rowCnt = pstmt.executeUpdate(); // 나머지 sql문

// 처리 끝난 후 자원 반납
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(conn != null) conn.close();

보이는 문제점들

간단한 sql을 실행하는데 중복된 코드를 계속 작성해야함..
자원을 제대로 반환해주지 않으면 버그 발생..
DB에 따라 일관성 없는 정보를 가진 채로 Checked Exception 처리..


Persistence Framework

JDBC 프로그래밍의 복잡함이나 번거로움 없이 간단한 작업만으로 데이터베이스와 연동되는 시스템을 빠르게 개발

SQL Mapper와 ORM으로 나눌 수 있다


SQL Mapper

객체와 SQL 문을 매핑하여 데이터를 객체화하자!

주의할 점: 객체와 관계를 매핑하는 것이 아니라 직접 작성한 SQL문의 질의 결과와 객체의 필드를 매핑하여 데이터를 객체화한다.

MyBatis

MyBatic가 data aceess 하는 순서에 대한 그림

스프링 부트에서 MyBatis를 사용할 경우 우리는 DB에 접근하기 위한 별다른 작업 없이
Mapper Interface 와 Mapping File (.xml) 만 구현하면 객체의 필드와 SQL문이 맵핑이 되게 된다!

장점

자동으로 Connection 관리를 해주면서 JDBC를 사용할 때의 중복 작업 대부분을 없애준다.
복잡한 쿼리나 다이나믹하게 변경되는 쿼리 작성이 쉽다
관심사 분리
DAO로부터 SQL문을 분리하여 코드의 간결성 및 유지보수성 향상

BUT..

특정 DB에 종속적으로 사용하기 쉽다

DAO 개발이 매우 반복되는 작업, 테이블 필드가 변경될 시 이와 관련된 모든 DAO의 SQL문, 객체의 필드등을 수정해야한다.

SQL에 의존적인 개발..
객체 간의 관계는 사라지고 데이터베이스에 대한 처리에 집중하게 되어버린다

패러다임 불일치 문제

객체지향 (추상화, 상속, 다형성)
VS
RDB (데이터 중심의 구조)

객체지향으로 설계한 방식이 Database에 적용하기 너무 힘든데.. 내 설계가 잘못되었나..?


ORM (Object Relational Mapping)

이 문제를 해결하기 위해 ORM은 객체 간의 관계를 바탕으로 SQL문을 자동으로 생성하고 직관적인 메서드로 데이터를 조작하게 하여 해결!

JPA

업로드중..

가장 대표적인 JPA 표준 인터페이스 Hibernate

패러다임 불일치 문제

1. 상속

우리가 짜는 코드에는 상속이 필수이다 그러나 RDB 에는 상속이라는 기능이 없다!

abstract class Person {
	Long id;
    String name;
}
class Crew extends Person {
	String nickName;
}

이것을 RDB에 표현하기 위해
Person 과 Crew 의 공통 부분을 슈퍼타입으로 묶고 나머지를 서브엔터티로 구현하는 관계를 사용하면 상속과 가장 유사한 설계를 할 수 있다

하지만 이렇게 설계를 하게 된다면..

// crew 객체를 저장할 때 
INSERT INTO person ...
INSERT INTO crew ...
// crew 객체를 조회할 때 
SELECT p.*, c.*
FROM person p JOIN crew c
ON p.id = c.id;

너무 복잡하다..

JPA를 통해 해결!

jpa.persist(album);
Crew crew = jpa.find(Crew.class, crewId);

2. 연관관계

class Crew{
	Long id;
    String nickName;
    Team team;
}
class Team{
	Long id;
    String name;
}

객체는 참조를 사용해서 다른 객체와 연관관계를 가지고, 테이블은 외래키를 사용해 다른 테이블과 연관관계 가진다.

만약에 DB 설계에 맞추기 위해 CREW 필드에 Team team 이 아닌 FK 컬럼을 넣어준다면

class Crew{
	Long id;
    Long teamId; // Team FK 컬럼 사용 
    String nickName;
}

물론 편리해질 순 있지만 객체지향의 특징을 잃어버리게 된다...

이번엔 객체지향으로 설계해보자

class Crew{
	Long id;
    Team team;
    String nickName;
    
    Team getTeam() {
    	return team;
    }
}

객체지향은 완벽하지만 테이블 기준으로 본다면 저장하거나 조회하기가 조금 복잡해진다..
하나의 crew 객체를 쪼개서 crew와 team 각각의 테이블에 나누는 로직을 생각해야한다

JPA로 해결!

crew.setTeam(team); // 크루와 팀의 관계를 설정
jpa.persist(crew); // 객체를 저장

Crew crew = jpa.find(Crew.class, id); 
Team team = crew.getTeam();

크루와 팀의 관계를 설정하고 persist로 객체를 저장하면 JPA가 team의 참조를 외래키로 변환하여 INSERT 문을 날리고, 조회할때도 내부적으로 외래키를 참조하여 처리한다

  1. 객체 그래프 탐색
    반환한 엔티티를 신뢰하고 사용할 수 없다.
  2. 비교
    DB는 기본키의 값으로 각 row를 구분 vs 객체는 동일성 비교와 동등성 비교로 구분

이러한 패러다임 불일치 들도 JPA가 해결해준다!


정리

그렇다면 ORM(JPA)이 짱일까..?

음 내가 생각했을때는 그런거 같다 JPA의 장점을 정리하면

  1. 패러다임 불일치 문제 해결 -> 객체 지향적으로 코드를 작성하기 편함!
  2. 생산성 -> 지루한 CRUD용 SQL 작성 필요없어짐
  3. 데이터 접근 추상화, 벤더 독립성 -> 데이터베이스마다 미묘하게 다른 문법 해결
  4. 유지보수 -> 쿼리를 수정하는 것이 아닌 엔티티를 수정

단점으로는 복잡한 쿼리 사용이 어렵다..?
JPA에서 SQL과 유사한 기술인 JPQL을 지원하고 또한 SQL 자체 쿼리도 작성할 수 있도록 지원해준다. 그래서 SQL Mapper와 혼용해서 사용도 가능하다!

찐 정리 : 장점이 너무나 강력한 JPA 공부해서 SQL Mapper와 혼용하여 장점을 다 챙겨야 한다!


참고자료

[10분 테코톡] ⏰ 아마찌의 ORM vs SQL Mapper vs JDBC

[Java] JDBC란 무엇인가? - Java Database Connectivity
출처: https://ittrue.tistory.com/250 [IT is True:티스토리]

SQL Mapper 와 ORM 기술의 차이

profile
기록하고 공유하는 개발자

0개의 댓글