ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ORM - ORM과 문제 해결1(상속)
    FrameWork/ORM 2024. 1. 22. 08:51

    ORM과 문제 해결 1

    ORM 기술은 이런 문제를 어떻게 해결할까? 우선은 OMR 중에도 JPA를 통해 ORM 기술이 이 문제를 어떻게 해결하는지 간단히 알아보자

     

    JPA를 사용하면 객체를 데이터베이스에 저장하고 관리할 때, 개발자가 직접 SQL을 작성하는 것이 아니라 JPA가 제공하는 API를 사용하면 된다. JPA가 개발자 대신에 적절한 SQL을 생성해서 데이터베이스에 전달한다. 

    JPA가 제공하는 CRUD API를 간단히 알아보자. 

     

     

    ▼저장 기능

    jpa.persist(member); //저장

     

    persist() 메소드는 객체를 데이터베이스에 저장한다. 이 메소드를 호출하면 JPA가 객체와 매핑 정보를 보고 적절한 INSERT SQL을 생성해서 데이터베이스에 전달한다. 매핑정보는 어떤 객체를 어떤 테이블에 관리할지 정의한 정보이다.

     

     

    ▼조회 기능

    String memberId = "helloId";
    Member member = jpa.fing(Member.class, memberId); //조회

     

    find()메소드는 객체 하나를 데이터베이스에서 조회한다. JPA는 객체와 매핑정보를 보고  적적한 SELECT SQL을 생성해서 데이버베이스에 전달하고 그 결과로 Member객체를 생성해서 반환한다.

     

    ▼수정 기능

    Member member = jpa.find(Member.calss,memberId);
    member.setName("이름변경"); //수정

     

    JPA는 별도의 수정 메소드를 제공하지 않는다. 대신에 객체를 조회해서 값을 변경만 하면 트랜잭션을 커밋할 때 데이터베이스에 적절한 UPDATE SQL이 전달 된다.

     

    ▼연관된 객체 조회

    Member member = jpa.find(Member.calss, memberId);
    Team team = member.getTeam(); //연관된 객체 조회

     

    JPA는 연관된 객첼르 사용하는 시점에 적절한 SELECT SQL을 실행한다. 따라서 JPA를 사용하면 연관된 객체를 마음껏 조회할 수 있다. 

     

    지금가지 JPA CRUD API를 간단히 알아보았다. 수정 기능과 연관된 객체 조회에서 설명한 것처럼 JPA는 SQL을 개발자 대신 작성해서 실행해주는 것이 이상의 기능들을 제공한다.


    🔬 다음은 객체와 관계형 데이터이스의 패러다임 차이 때문에 발생하는 다양한 문제를 살펴보고 JPA는 이런 문제들을 어떻게 해결하는지 알아 보자

     

    ⭐패러다임의 불일치

    애플케이션은 발전하면 그 내부의 복잡성도 점점 커진다. 지속가능한 애플리케이션을 개발하는 일은 끊임없이 증가하는 복잡성과의 싸움이다. 복잡성을 제어하지 못하면 결국 유지보수하기 어려운 애플리케이션이 된다.

     

    객체지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치를 제공한다. 그래서 현대의 복잡한 애플리케이션은 대부분 객체지향 언어로 개발한다.

     

    비지니스 요구사항을 정의한 도메인 모델도 객체로 모델링하면 객체지향 언어가 가진 장점들을 활용할 수 있다. 문제는 이렇게 정의한 도메인 모델을 저장할 때 발생한다. 예를 들어 특정 유저가 시스템에 회원 가입하면 회원이라는 객체 인스턴스를 생성한 후에 이 객체를 메모리가 아닌 어딘가에 영구 보관해야 한다.

     

    객체는 속성(필드)과 기능(메소드)을 가진다. 객체의 기능은 클래스에 정의되어 있으므로 객체 인스턴스인 상태의 속성만 저장했다가 필요할 때 불러와서 복구하면 된다. 객체가 단순하면 객체의 모든 소성 값을 꺼내서 파일이나 데이터베이스에 저장하면 되지만, 부모 객체를 상속 받았거나, 다른 객체를 참조하고 있다면 개체의 상태를 저장하기는 쉽지않다. 예를 들어 회원 객체를 저장해야 한느데 회원 객체가 팀 객체를 참조하고 있다면, 회원 객체를 저장할 대 팀 객체도 함께 저장해야한다. 단순히 회원 객체만 저장하면 참조하는 팀 객체를 잃어버리는 문제가 발생한다.

     

    자바의 경우는 이런 문제까지 고려해서 객체를 파일로 저장하는 직렬와 기능과 저장된 파일을 객체로 복구하는 역 질열화 기능을 제공한다. 하지만 이 방법은 직렬화된 파일을 객체로 검색하기 어렵다(Java 언어의 api를 이용한 검색이 어렵다.)는 문제가 있으므로 현실성이 없다. 현식적인 대안은 관계형 데이터베이스에 객체를 저장하는 것인데, 관계형 데이터베이스는 데이터 중심으로 구조화되어 있고, 집합적인 사고를 요구한다. 그리고 객체지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 없다.

    💡tip) 직렬화(serialization)와 역직렬화(deserialization)

    직렬화는 객체를 저장 가능한 상태(ex 메모리, DB, 파일 등) 혹은 전송 가능한 상태(ex 네트워크 상의 데이터 스크림 형태)로 변환하는 것을 의미한다. 쉽게 말해 직렬화는 객체를 저장, 전송할 수 있는 특정 포맷 상태로 바꾸는 과정이라고 할 수 있다.

    역직렬화는 말 그대로 직렬화의 반대 이다. 즉, 특정 포맷 상태의 데이터를 다시 객체로 변환하는 것을 의미한다.

    일반적으로 Java에서의 직렬화는 객체를 Binary형태로 변환하는 것을 의미한다. disk에 객체를 저장하거나 컴퓨터 네트워크 상의 객체를 전송하고 싶다면 Binary 형태로 바꿔야지만 가능한다. 객체 그 자체는 disk나 네트워크 장비가 이해할 수 없을 것이다.

    출처
    https://code-lab1.tistory.com/289

     

    객체와 관계형 데이터베이스는 지향하는 목적이 서로 다르므로 둘의 기능과 표현 방법도 다르다. 이것을 관계형 데이터베이스의 패러다임 불일치 문제라고 한다. 따라서 객체 구조를 테이블 구조에 저장하는 데 한계가 있다.

     

    상속

    1.2 객체 상속 모델

    그나마 데이터베이스 모델링에서 이야기하는 슈퍼타입 서브타입 관계를 사용하면 객체 상속과 가장 유사한 형태로 테이블을 설계할 수 있다. 아래 그림 1.3에서 ITEM테이블의 DTYPE 컬럼을 사용해서 어떤 자식 테이블과 관계가 있는지 정의했다. 예를 들어 DTYPE의 값이 MOVIE이면 영화 데이블과 관계가 있다.

     

     

    객체 모델 코드

    abstract class Item{
        Long id;
        String name;
        int price;
    }
    
    class Album extends Item{
        String artist;
    }
    
    class Movie extends Item{
       String director;
       String actor;
    }
    
    class Book extends Item{
       String author;
       String isbn;
    }

     

    Album 객체를 저장하려면 이 객체를 분해해서 다음 두 SQL을 만들어야 한다. 

    INSERT INTO ITEM ...
    INSERT INTO ALBUM ...

     

    Movie 객체도 만찬가지다

    INSERT INTO ITEM ...
    INSERT INTO MOVIE ...

     

    JBDC API를 사용해서 이 코드를 완성하려면 부모 객체에서 부모 데이터만 꺼내서 ITEM용 INSERT SQL을 작성하고 자식 객체에서 자식 데이터만 꺼내서 ALBUM용 INSERT SQL을 작성해야 하는데, 작성해야 하는 코드량이 만만치 않다. 그리고 자식 타입에 따라서 DTYPE도 저장해야 한다.

     

    조회하는 것도 쉬운 일은 아니다. 예를 드어 Album을 조회한다면 ITEM과 ALBUM테이블을 조인해서 조회한 다음 그 결과로 Album객체를 생성해야 한다. 이런 과정이 모두 패러당미 불일치를 해결하려고 소모하는 비용이다. 만약 해당 객체들을 데이터 베이스가 아닌 자바 컬렉션에 보관한다면 다음 과 같이 부모 자식이나 타입에 대한 고민 없이 해당 컬렉션을 그냥 사용하면 된다.

    list.add(album);
    list.add(movie);
    
    Album album = list.get(albumId);

     

    JPA와 상속

    JPA는 상속과 관련된 패러다임의 불일치 문제를 개발자 대신 해결해 준다. 개발자는 마치 자바 컬렉션에 객체를 저장하듯이 JPA에게 객체를 저장하면 된다. 

     

    JPA를 사용해서 Item을 상속한 Album 객체를 저장해보자. 앞서 설명한 persist()메소드를 사용해서 객체를 정하하면 된다.

    jpa.persist(album);

    JPA는 다음 SQL을 실행해서 객체를 ITEM,ALBUM 두 테이블에 나누어 저장한다.

    INSERT INTO ITEM ...
    INSERT INTO ALBUM ...

     

    다음으로 Album객체를 조회해보자. 앛서 설명한 find() 메소드를 사용해서 객체를 조회하면 된다.

     

    String albumId = "id100";
    Album album = jpa.find(Album.class,albumId);

    JPA는 ITEM과 ALBUM 두 테이블을 조인해서 필요한 데이터를 조회하고 그 결과를 반환한다.

     

    출처 - [자바 ORM 표준 JPA 프로그래밍 - 저, 김영한]

    http://www.acornpub.co.kr/book/jpa-programmig\

     

    자바 ORM 표준 JPA 프로그래밍

    JPA 기초 이론과 핵심 원리, 그리고 실무에 필요한 성능 최적화 방법까지 JPA에 대한 모든 것

    www.acornpub.co.kr

     

    댓글

Designed by Tistory.