JPA 가 뭔데 쓰는건가요?
Spring을 공부하던 중에, 멘토님께서 JPA의 중요성을 강조해주셨습니다. Django 는 ORM 으로 간단하게 DB를 다루고 쓸 수 있었는데, Spring에서는 어떤 식으로 DB에 접근하고 데이터를 읽어오는 지 궁금해졌습니다.
설마 학교에서 하던 것 처럼 현업에서 직접 DB에 커넥션 맺고 길고 긴 코드로 가져오는 건 아닐테니 말입니다. 🤨
이 포스트에서는 JPA가 무엇인지, 왜 등장했는지와 QueryDSL 에 대한 간략한 소개를 다룹니다.
JPA(Java Persistent API)
관계형 데이터를 관리하는 자바 프로그래밍 인터페이스.
이게 무슨 말이니?
Database에 접근해서 원하는 정보를 얻어낼 수 있게 해준다는 뜻
RDB를 객체로 매핑해서 사용!
![](../img/2018-10-08/scrn 2.png){: style="width:50%; display: block; margin:100px auto 0;"}{: style="display:block;margin-top:10px;color:#828282;font-style:normal;text-align:center"}
위와 같은 RDB를
다음과 같은 오브젝트로 만들어서
처럼, 자바코드에서 DB에 기록된 정보를 자유롭게 쓸 수 있게 해준다는 뜻!
이전에는 어떻게 했는데?
JDBC
DB connection 을 맺는다.
쿼리를 생성한다.
String query = "select id, name, password from User where id = " + user.getId();
쿼리를 실행한다.
ResultSet rs = stmt.executeQuery(selectQuery);
오브젝트에 일일히 데이터 매핑
user.setId(rs.getInt("id"); user.setName(rs.getString("name");
DB Connection을 종료한다.
이런 방식은 SQL injection의 위험 등 보안 문제가 있다. 예를 들어 위의 user id 에 id 뿐 아니라 원하는 쿼리문을 넣으면, 해당 사용자가 원하는 정보를 빼낼 수 있다.
더불어 Connection 을 맺고 끊음에 있어서, 예외처리 관련 코드가 계속 반복적으로 많이 나오게 된다.
MyBatis (로 대표되는 SQL Mapper)
iBatis, MyBatis 로 대표되는 SQL Mapper 들은 Query 와 데이터의 패러다임
이다.
이러한 SQL 들은 별도의 XML 파일로 연결되며 파라미터와 실제 오브젝트를 연결해주는 식으로 진행된다.
JDBC에 비해서
- Connection을 맺는 작업(#1), Connection Close 작업(#5)를 알아서 해줌
- 파라미터 매핑과 데이터 매핑도 위임
하지만
- 여전히 쿼리를 작성해야함.
다만 MyBatis 는 쿼리를 작성할 수 있다는 점때문에 복잡하게 쿼리를 날려서 로깅하는 경우 유용하다.
그럼 ORM → JPA는
ORM 은 Table이나 query 가 아닌 객체 중심의 사고를 해보자! 하고 등장한 존재이다.
Connection 맺기 / 끊기 위임 쿼리를 자동 생성 실행! ( Query Method) 파라미터 매핑과 데이터 매핑은 필요도 없음
모든 Domain은 변경사항이 있다.
이때 코드가 짧아 변경사항이 적고 type-safe 할 수 있도록 도와준다는 큰 장점이 있음
영속 / 준영속 / 비영속
말이 너무 어렵다!
코드로 보자
즉 비영속상태
는 객체가 만들어지기만 하고 어디에도 저장되지 않은 상태
영속상태
는 persist
명령어를 통해서 1차로 캐시에 저장된 상태
준영속상태
는 close
시점에서 저장소에 SQL 쿼리가 반영되어, 더 이상 캐시에서 다룰수는 없는 상태 를 의미함. Detached
라는 말이 더욱 어울릴 듯함.
JPA 소개
@Entity
: Bean객체임을 의미한다@Table
: 매핑되는 테이블 이름을 지정@Id
: 이 테이블의 Id임을 말함.@GeneratedValue
는 자동으로 생성됨@Column
: 특별히 column의 속성을 지정해주고 싶거나 이름을 정하고 싶을 때 사용. 디폴트로는 멤버 변수명과 일치하는 데이터베이스의 칼럼을 매핑합니다.
Repository Interface
Repository 인터페이스는 다음처럼 사용한다.
Repository 를 구현하면 다음과 같은 기본 기능들을
- Save(T)
- Delete(Y)
- FindAll()
- FindByID()
추가 설정이나 코드 없이 바로 사용할 수 있다.
CRUD 외에 다른 코드가 필요하다면 추가하면 된다.
참고 - Spring Data JPA Reference Documentation
위 링크를 참조하면 메소드 이름 만으로 쿼리를 만들어 낼 수 있음을 알수있다.
이를 QueryMethod 라고 한다. 정확히는 JPQL 이라는 쿼리를 만들어낸다.
예를 들어, Name과 email로 유저를 Select하는 쿼리를 날리고 싶다면 정해진 룰에 따라
findBy + Name + And + Email
이라는 이름의 메소드를 만들기만 하면 원하는 쿼리가 만들어진다.
물론 따로 쿼리를 작성할 수 도 있다.
이렇게 Repository 를 구성하고 사용하면된다.
아래와 같이 UserRepository 를 @Autowired
annotation으로 주입해준다.
JQPL을 보완하는 QueryDSL
JPA에서 사용하는 JQPL 질의언어는 String을 사용하기때문에 initial time에 오류를 알 수 있다.
runtime에 비하면 나쁘지 않지만, compile 타임에 에러를 잡고싶었다.
이를 보완하기 위해 나온 것이 QueryDSL이다.
QueryDSL은 별도의 Q 객체를 사용하며, 컴파일 타임에 쿼리 에러를 잡을 수 있다는 장점이 있어서
현업에서 JPA와 함께 쓰는 추세이다.