sql만 사용하면 문제점

XingXi·2023년 12월 20일
0

JPA

목록 보기
1/23
post-thumbnail

🍕 Reference

자바 ORM 표준 JPA 프로그래밍 : 교보문고
자바 ORM 표준 JPA 프로그래밍 - 기본편 : 인프런

쓰기전

JPA를 사용하면서 제대로 알아본 적이 없다고 생각이 들어 강의와 책을 통해서 정리해 나가려고 합니다. 많이 부족하기 때문에 틀린 부분 있으면 편하게 말씀해주세요!

🍕객체지향과 관계형 데이터 베이스


DB-Engines Ranking

2023년 12월 기준 데이터베이스 사용 순위를 보면 관계형 데이터 베이스를 많이 사용하는 것을 알 수 있다.
객체 지향 프로그램을 통해 현실 세계의 모델을 반영하여
관계형 데이터 베이스에 저장함으로써 현실 세계 모델을 표현하기 쉽다는 이점 때문일 것이다.
객체 지향 언어인 자바를 사용하여 관계형 데이터 베이스의 데이터를 조작하려고 한다.
하지만 여기에는 큰 문제점들이 몇 가지가 있다.


🍕문제점

1. 많은 양의 쿼리 작성 및 SQL 에 의존적이다.

이미지 참조

당연한 말이겠지만 Programming 언어를 사용하여 DB 에 있는 데이터를 다루기 위해서는
SQL Query 를 정의하여 CRUD 를 수행해야한다. 대략적인 순서를 생각해 보자

1. DB에서 불러온 데이터를 조작하기 위한 객체를 정의한다.
2. 가져올 데이터를 특정하기 위한 SQL Query 를 언어로 작성
3. DAO 에서 Query 가 실행 되고 해당 데이터를 객체에 저장하도록 정의한다.
4. 비지니스 로직을 구현한다.

이러한 일련의 과정들이 서비스에 따라 추가가 될 것이고 테이블 구조의 변경이
있을 경우 유지보수 하기 힘들어 진다.
또한 Query 에 따라 받아 올 수 있는 데이터 또한 한정적이라서 Query 에 의존하여 작성할 수 밖에 없다.

요약

1. 반복적인 작업들이 늘어난다.
2. 테이블의 구조가 변경 될 경우 유지보수량이 많다.
3. SQL에 따라 데이터가 한정적이기 때문에 SQL Query 에 의존적이다.


2. 객체지향과 관계형 데이터 베이스의 패러다임이 맞지 않아 생기는 문제가 많다.

관계형 데이터베이스는 데이터 중심으로 구조화 되어 있고
객체 지향의 추상,상속,다형성 같은 개념이 존재하지 않는다. 이로 인해 생기는 다양한 문제들이 있다.

a. 상속

class Gv80 extend CAR
{
	public Gv80(){super();}
}

// Car 인스턴스 생성 이후 Gv80 인스턴스 생성 

객체는 보기 처럼 기본 생성자가 숨겨져있다.
해당 객체 Gv80 이라는 클래스의 객체를 new 연산자를 이용하여 생성하면
기본 생성자 내부의 super() 가 호출이 되어 Car 객체의 인스턴스가 먼저 생성될 것이다.

관계형 데이터 베이스에서 상속을 구현하기 위해
계층처럼 부모 역할, 자식 역할 하는 테이블을 만들어 슈퍼타입 서브타입 관계로 설정할 수도 있지만
완전 일치하지 않으며 복잡성이 늘어나고 조회할 때마다 JOIN Query 가 추가되어야한다.

테이블에 Gv80 객체 데이터를 저장하는 경우
Gv80 객체를 DB 에 저장하는 경우 Car 데이터를 저장하는 SQL Query,
Gv80 데이터를 저장하는 SQL Query가 적성되어야한다.

Gv80 를 조회하는 경우
Gv80 테이블과 Car 테이블을 조회하는 Query 를 작성한다.

b. 연관관계

연관관계에서도 차이가 있다.
객체의 연관관계는 참조를 이용하고
테이블의 참조는 외래키를 이용한다

CASE A

class TestA
{
	String id;
	TestB  testb;
}

class TestB
{ String id; }

CASE B

TestA testA = new TestA(Object);

testA.getTestb().getId() 

***
OR
***
 
class TestA
{
	String id;
	String testb_id;
}

class TestB
{ String id; }

객체는 다음과 같이 TestA 클래스TestB 타입의 testb 라는 필드를 모델링하여
연관관계를 정의하지만 테이블은 외래키를 사용하여 연관관계를 정의하기 때문에
Query 작성 시 testb 의 id 값을 리턴 받게 하는 변환작업(testA.getTestB().getId()) 이 필요하거나
CASE B 처럼 TestB의 Id 값을 TestA 의 필드로 모델링하여 사용해야한다.

이처럼 연관관계 정의의 차이 때문에
테이블에 맞춰서 객체를 모델링 하여 객체의 이점을 온전히 사용하지 못하는 문제점이 있다.

c. 그래프 탐색

또 참조를 사용하여 연관 관계 탐색을 하기 때문에 객체는 다음과 같이 그래프 탐색이 가능하다

  • 객체 그래프 탐색을 사용하는 경우
class TestA
{
	Long  pid   ;
	TESTB testb ;
}

class TestB
{
	Long  pid   ;
	TESTC testc ;
}

class TestC
{
	Long pid         ;
	String name;
}

...
String testCName = testA.getTestb().getTestC().getName();
  • 그래프 탐색을 위해 여러개의 Join Query 를 생성
  1. String testCName = testA.getTestb().getTestC().getName(); 사용 가능 ( TestA, TestB, TestC 불러옴 )
select C.testC_Name 
from TestA A
JOIN TestB B ON A.testB_Pid = B.pid
JOIN TestC C On B.testC_Pid = C.pid 
WHERE A.pid = 입력값
  1. String testCName = testA.getTestb().getTestC().getName(); 사용 불가능 ( TestA, TestB 만 불러옴 )
select C.testC_Name 
from TestA A
JOIN TestB B ON A.testB_Pid = B.pid
WHERE A.pid = 입력값

하지만 데이터베이스에 데이터를 가져오는 경우

SQL Query에 따라 DB 에서 가져오는 데이터가 한정 되어 지기 때문에
자유로운 그래프 탐색을 수행하지 못한다.

그래프 탐색의 자유롭지 못한 경우
해당 엔티티의 계층 값들이 할당되지 않을 수 있기 때문에 엔티티를 신뢰할 수 없어진다.

모든 참조를 불러올 수 있는 쿼리를 작성하여 사용하는 것은 효율적이지 못하기 때문에
연관 관계에 마다 데이터를 불러오는 JOIN Query 를 작성하고 이에 따른 작업량이 증가한다.

요약

객체와 관계형 데이터 베이스 간의 패러다임 불일치로 인해 다음과 같은 문제를 생각해 볼 수 있다.


1. 객체를 생성하면 상속된 상위 객체를 함께 생성하지만 데이터 베이스에서는
상속 개념이 존재하지 않고 Super, Sub Type 으로 구현한다고 하더라도 한계가 명확하다.


2. 객체는 연관 관계를 참조를 이용해서 표현하지만 관계형 데이터 베이스 에서는
외래키를 사용하기 때문에 연관 관계를 조회하기 위한 JOIN Query 가 필요하고
외래키를 필드로 같는 등의 SQL 에 맞추어 객체 모델링이 진행된다.


3. 객체는 연관 관계를 참조를 이용하기 때문에 자유로운 그래프 탐색이 가능하다.
하지만 RDB 의 경우 Query 에 따라서 데이터가 제한적이기 때문에
그래프 탐색의 데이터가 제한적이게 되고 엔티티 신뢰도 문제도 발생한다.

0개의 댓글