JPA 등장배경

roach·2020년 12월 17일
0

JPA

목록 보기
1/2
post-thumbnail

역사

우리가 기술을 공부하는데 있어서, 제일 그 기술을 쉽게 이해하기 위해서는 그 기술의 등장 배경을 알아야 한다고 생각한다. 왜 만들었는지를 알면, 그 기술이 동작하고자 하는 바를 알 수 있다.

JPA 등장 배경 ?

이 부분은 사실 잘 몰랐는데, 우아한 유튜브 에서 보고 알게 되었다.
웹 통신 그리고 기술의 발전으로 인해 DB 의 중요성이 점점 더 높아졌고, 각 언어들에서도 DB와 연동할 수 있는 기술들이 필요하게 됬다. 그래서 처음에는 단순한 DB Connection 을 위한 프레임워크들이 나오기 시작했다.

하지만 우리가 한번이라도 쿼리를 직접쳐봤다면 느낄 것이다. 쿼리는 실수가 많을 수 밖에 없고, 인간이 그걸 하나하나 치기에는 너무 귀찮다.. 사실 DB connection 만 자동으로 해주는 것도 엄청난 기술이였을 것이다. 그래도 프로그래밍은 귀찮은걸 쉽게 하기 위해 발전 된다 생각하므로, 사람들은 조금 더 이 쿼리를 강력하고, 신뢰성 있게 쓰기를 원했다.

그래서 나온것이 SQLMapper 시리즈 중 하나인 MyBatis 이다.
MyBatis 는 xml 을 이용하여 쿼리를 통제하고자 하였다. 기존에는 자바 코드에서 String 을 이용하여, query를 입력하고 있었다. 예를들면
pstm.query("select * from Table") 이런 식으로 말이다.
근데 이 방법은 String 이기에 띄어 쓰기도 힘들고, 해보면 알겠지만 오타에 화가 머리 끝까지 치밀어 오른다.

그래서 관심사를 분리하여 XML 파일로 Query 를 분리하였다.

근데 이렇게 SQL 을 위주로 설계하다보니, 객체 지향적으로 설계할 수 없게 되었다. 왜냐? 만약 우리가 Member 라는 Table 에 이름 그리고 나이만 있었다고 해보자. 그럼 Member Table 과 Member Class 는 아래와 같이 정의 될 것이다.

class Member{
	private String name
    	private int age
}
[Member]
--------
[name]
[age]

근데 여기서 Member Table 에 Team 이라는 것을 추가해 달라고 요구사항이 들어왔다. 그래서 Member.update(team1_input_dto) 을 했는데, 어, 쿼리는 정상적으로 갔는데 업데이트가 되지 않았다. 알고보니 Team Column 을 Update 를 하지 않은 것이다. 그래서 Team 을 보려고 했더니, 알고보니 Team 은 객체지 않은가..? 그래서 개발자가 부랴부랴 Team.getTeamName() 으로 수정하여 Team 이름을 DB에 insert 하였다...
그러다 보니 개발은 객체 지향이 아닌, SQL 에 의존하는 개발 방식을 사용할 수 밖에 없었고, 객체 지향을 사랑하는 사람들은 객체 지향적으로 코드를 설계하기 를 원했다. 그래서 등장한것이 ORM 이다.

이정도로 알고 일단은 넘어가자 ! 이 정도만 알아도 왜 등장 했는지는 알 수 있을 것이다.

영속성(Persistence)

  • 영속성?? 우리는 태어나서 처음듣는 말일 수 있다. 쉽게 얘기하면 지속적인 것이라고 생각하면 된다. 프로그래밍 상으로는 프로그램이 종료되더라도 없어지지 않는 데이터의 특성을 말한다. 엥? 근데 데이터베이스인데 프로그램이 종료되면 없어진다고요? 라고 말할 수 있다. 근데 영속성은 그 앞전 시대, 그니까 프로그램이 돌때 RAM, 즉 휘발성 메모리에서 지속되는 데이터들이 있는데, 해당 데이터들은 프로그램이 종료되면 없어지게 된다. 프로그래머들은 이러한 데이터들을 지속적으로 유지하고 싶어했고, 그래서 영속성이란 개념이 등장한 것 이다. 그래서 데이터들을 지속적으로 유지하기 위해 DB 에 Data 들을 저장하기 시작했고, 데이터들은 사라지지 않고 지속적으로 유지될 수 있었다. 근데 이 얘기를 왜했느냐? JPA 에서 영속성이라는 개념이 등장하기 때문이다. 그럼 JPA 는 뭘 지속적으로 저장하고 싶었을까? 바로 영속성 컨텍스트(Persistence Context) 에 Entity 를 영구히 저장하고 싶었다. 그래서 우리는 Persistence Context 의 관리자, 즉 PersistenceManager 를 통해 영속적으로 저장된 Entity 들을 관리할 수 있는 것이다. 이제 좀 JPA 의 영속적 개념이 이해가 가는가?

ORM 의 등장?

그럼 우리가 JPA 그니까 영속적으로 Entity 를 저장해서 얻을 수 있는 장점이 뭔데? 라는 질문을 던질 수 있다. 당연하다 이런 질문이 나오는 것이. 굳이 쓸만한 이유를 알아야 그 기술을 제대로 사용할 수 있기 때문이다.

자 그럼 알아보자! 우리가 객체 지향을 설계할때 가장 중요한 5가지를 말하라고 하면 항상 나오는 추상화, 캡슐화, 정보은닉, 상속, 다형성 등이 있다. 근데 SQL 에 의존적으로 설계하다 보면, 객체를 저장하는 것에서 상당한 문제가 생긴다. 객체를 이곳저곳 연관지어 저장하다보면, 참조값을 잃을 수도 있기 때문이다. 그래서 객체의 이름 혹은 고유적인 값으로 저장하여야 하는데, 이것이 엄청 복잡하다. 그래서 ORM 이 등장한것이다. 우리는 객체의 관의 관계 만으로도 설계가 가능하다! 즉 객체 지향적으로 설계가 가능해! 라고 말하는 프레임워크가 등장한 것이다.

그럼 다시 돌아가서 JPA 에서는 이것을 어떻게 처리할까? 어떻게 객체를 처리하지? 라고 묻는다면 Persistence 가 해답이다. 우리가 영속적으로 저장하고 관리하는것이 필요한 이유는 다 이녀석들 때문이다.
우리가 아까 위의 예시대로 EntityManger.persist(team) 으로 객체를 저장하게 되면, JPA 가 이를 처리해준다 정말 멋진 기술이다. 👍👍

우리는 이로써 SQL 중심의 설계에서 도메인 중심의 설계로 방향을 이전할 수 있게 되었다. 또한 객체 지향적으로 코드를 설계할 수 있게 되었다!

JPA 장점?

그럼 모두가 많이 사용하는 JPA는 과연 장점이 저것 하나일까? 아니다 다른 장점들도 존재한다. 저거 하나 뿐이라면, JPA 는 지금처럼 쓰지 못했을 것일 뿐더러, Persistence Context 를 더욱더 활용해야 한다. 그래서 우리가 저장한 Entity 들은 Persistence 안에 Key-Value 를 가진 1차 캐시에 저장된다. 따라서 Entity 에는 반드시 Key🔑 (고유한 식별자) 가 필요하다! 그 기능은 Entity의 Primary Key 가 담당한다.

그래서 DB에 조회하기전 JPA 는 1차적으로 자신의 Cache 를 먼져 탐색한다. 우리가 CS 지식으로 알듯이 Cache 는 엄청나게 빠른 속도를 가지고 있다. 그래서 탐색 속도 측면에서 상당한 시간적 이득을 챙길 수 있다. 이것이 JPA 가 제공하는 1차 Cache 기능이다!

이제 만약 Cache 를 탐색했는데도 Data 가 없다면 우리의 JPA 는 DB 로 머나먼 여행을 떠난다. JPA 는 값을 꺼내온 후 ! 자신의 1차 Cache 에 해당 Data 를 Key-Value 로 저장한다. 다음에 탐색할때는 더 빠르게 찾기 위함이다! 정말 대단한 프레임워크이다.

또한 쓰기 지연 이라는 기능을 제공한다. 얼핏 들으면 무슨 소리지 싶다! 쓰기를 지연하는게 장점이라고?? 우리는 여기서 트랜잭션이라는 개념을 알아야 한다. 트랜잭션이란? 상태를 변화시키는 것? 이라고 간단하게 이해하면 된다. 그래서 우리가 데이터의 상태를 변화시키기 위해 쿼리문들을 작성하면 그것들은 JPA 내의 쓰기 지연 SQL 저장소에 저장된다 그리고 우리가 트랜잭션을 Flush 하거나 Commit 할때 해당 Query 들이 발송된다.🚀

즉 우리가 트랜잭션을 Commit 혹은 Flush 하기 전까지 DB 의 상태 변화는 없다는 것이다. 이 점이 엄청난 장점인 것을 눈치 챘다면 당신은 영속성을 이제 이해하고 있는 것이다. 즉 우리는 DB 의 Query를 쏘지 않고도, DB 와 연관된 값들을 변경시킨 것이다. 이게 Persistence Context 가 존재하는 이유이자, 제일 중요한 개념인 이유다.

자 그럼 우리가 DB에 값을 다시 Update 하고 싶으면 Update 쿼리를 다시 쏴야 할까? 그건 JPA에게는 너무 구식적인 방법이자, 객체지향적인 방법이 아니다. 왜냐? 그럼 콜럼이 늘수록 update() funtion을 overload 하거나 수정해야 할텐데, 그럼 또 다시 SQL 중심의 개발로 돌아가는것과 마찬가지다.

우리는 등장이유를 알기에 JPA 는 이러한 방식을 사용하지 않을 것이라는 것도 눈치챌 수 있다. 그럼 JPA 에서 사용하는 Dirty-Checking 에 대해 알아보자! (=> 이건 TS, JS 의 Observable 개념과 흡사하다!)

자여기서 1차 Cache 를 다시 불러오자! 우리는 영속성 컨텍스트가 이제 JPA의 중점 기술인 것을 알기에 우리가 어떻게 Entity 가 바뀐걸 감지하지? 라고 생각한다면, Entity를 저장하는 1차 Cache 에서 이뤄진다고 추축해 볼 수 있다. 우리는 1차 Cache 에 Entity의 Snapshot 을 저장하게 되는데, 우리가 set Method 혹은 일련의 값을 바꿔주는 기능을 하게되면, 영속성 컨텍스트가 이를 감지하여, update query를 자동으로 작성한다. 정말 멋진 기능이지 않은가?
다만.. 이 update query 에는 치명적인 단점이자 장점 있다. 모든 Column 을 update 한다는 것이다. 이것이 query 문을 동적으로 변경안해도된다는 것에는 장점 일 수 있으나, 계속해서 모든 Column 을 update 하는것은 불필요한 work 일 수도 있다. 그래서 JPA 는 Annotation 을 통해 해당 기능을 지원한다. ( @org.hibernate.annotations.DynamicUpdate) 근데 이 기능은 나중에 알아보자! 지금은 아니다..

일단 첫 챕터는 이정도로 정리해 보았다. 우리가 이글을 읽으면 등장배경과 어려운 영속성? 이라는 단어도 어느정도는 이해할 수 있다고 생각한다.

저도 아직 초보라, 틀린것이 있을 수 있습니다. 계속해서 공부하고 느낀 것을 조금이라도 남들이 쉽게 이해할 수 있도록 설명하려고 적는 글이며, 개인적인 기술의 깊이를 넓히기 위해 적는 글이기도 합니다. 비난보다는 피드백! 겸허히 받아들이겠습니다. 틀린 부분이 있다면 댓글로 알려주세요!!

profile
모든 기술에는 고민을

0개의 댓글