티스토리 뷰

반응형

제목을 좀 거창하게 지은 것 같긴 하네요. 그냥, 제가 JOOQ 을 써보게 된 계기를 담담하게 적어보려고 합니다.


Java 을 오랜 기간동안 사용해서 개발하다보니, 당연히 Connection, PreparedStatement, ResultSet 을 이용해서 DB 에 질의(Query)을 하는 방법도 써왔고, iBatis 2.x ~ MyBatis 3 도 많이 사용했으며, Spring 의 JdbcTemplate 도 써본 적이 있습니다. 한 때 이슈가 된, 그리고 지지자들의 의견으론, 해외에선 이미 대세가 되었다는 ORM, 그 중에서도 Java 표준이 되어버린 JPA with Hibernate 을 이용해 게임 서버를 개발하여 출시도 해봤습니다.


여러 방식으로 RDBMS 에 질의를 했지만, 그래도 가장 나았던 건 MyBatis 3 였습니다. iBatis 2.x 을 처음 쓸 때에는 괜찮았지만, Java 의 버전이 높아지면서 형변환(cast) 문제가 발생하여 MyBatis 3 가 나오자마자 바로 갈아탔던 기억이 새록새록하네요. MyBatis 의 최대 장점은 역시 십 수어 장 정도의 가이드만 읽고도 빠르고 쉽게 기존 소스에 융합시키는게 쉽다는 점이죠. 그리고, SQL 을 그대로 이용할 수 있다는 장점 역시 저에게는 컸습니다.


반대로, JPA 는 아주 곤혹스러웠습니다. 최대한 Spring Data 스럽게 개발하기 위해 Spring Data JPA Repository 을 이용해서 쿼리 정의 없이 메서드(method) 명의 나열로 쿼리를 만들었는데, 이러한 부분이 개발 속도 향상에는 도움이 되었지만, 단순 질의가 많은 게임 서버 프로그램의 특성에 잘 맞는 편이긴 했지만, 역시나 몇몇 부분에선 문제를 일으켜 @Query, 나아가선 Native Query(@Query 에 nativeQuery = true 옵션 활성화) 선언도 해야했고, 그것조차 불가능해서 코드 상에서 직접 JPQL 을 만들어서 사용한 경우도 있었습니다.

이러한 일은 제가 SQL 에 대한 이해도가 매우 높기 때문에 발생하는 문제였습니다. 애초에 ORM 이라는 것이 DBMS 의 직접적인 제어가 아닌 Java 코드의 제어를 통해 DBMS 을 제어할 수 있는 코드를 생산해내고, DBMS 고유의 기능은 모두 위임하는 것이기 때문일 겁니다(맞나?). 하지만, 각 DBMS 마다 고유한 기능이 있을 것이고, 그것을 잘 아는 개발자들은 그 기능들을 이용해서 한결 간결하고 효율적인 명령을 만들어낼 수 있기 때문에, 이러한 부분은 분명 ORM 사용에 장애가 된 것이 사실이었습니다.


이후, 어이없게도 PHP 을 메인으로 하는 회사에 (속아서?) 입사하게 되었습니다. 그 곳에서, Java 초창기에 개발하듯 Connection 얻고 PreparedStatement(사실 대부분은 그냥 Statement 형태) 정의하고 ResultSet(PHP 는 array 로) 얻는 소스를 다시 만나게 되었습니다. 거의 10 년 이상 전으로 회귀한 셈이 된 것이죠. 꼭 나쁘다는 것은 아닙니다. 하지만, PreparedStatement 조차 쓰지 않는 것이 많다고 살짝 언급했듯이, 처리 방식이 좀 괴랄한 부분이 많았습니다. 그리고 사고를 한 번 쳤습니다.

망분리PC 에 긴 문장을 복사해넣고 이리저리 수정하다가 Table 명의 Alias 을 저의 습관대로 A, B, ... 이런 식으로 바꿔서 이리저리 하다가, 실제 소스에 붙여넣을 때 Field 의 Alias 와 다시 맞춰줘야 하는데, 그 부분을 놓치고 Table 의 Alias 만 A, B, ... 이런 식으로 그냥 둔 것이죠. 해당 부분은 비동기로 적용되는 부분이다보니 테스트 상황에서 재현을 하기 어려워 모르고 서비스에 적용되었다가 나중에 해당 기능이 동작을 안하는 것 같다는 사업관리자의 보고를 받고서야 인지하게 되었고, 덕분에 저는 장애보고서를 써야했습니다.

장애보고서에는 단순히 확인을 잘 하겠다라고 적었지만, 실제 구두상으로는 이러한 오류를 시스템적으로 검출할 수 있는 필요성이 있다고 제안을 드렸습니다. 그 때 당시 망분리PC 사용방법이 너무 짜증나서 그랬던 것도 있지만, 어쨌든 JPA 와 같은 것이 도입되어 있었다면 이런 Alias 문제는 존재하지 않았겠죠.


이후 Java 로 개발된 것들이 하나 둘씩 생기긴 했지만, 저는 여전히 JPA 에 대해서는 반대 입장이었습니다. 그래서 중간 접점을 찾고 있었는데, 그 때 제 눈에 들어온 것이 QueryDSL 와 JOOQ 였습니다. QueryDSL 은 모든 DBMS 에서 무료로 사용할 수 있는 반면, JOOQ 은 무료 DBMS 가 아니면 비용을 지불해야 하는 제품이었습니다. 이 시점에 새로운 일이 생겼는데, 직접 프로그램을 만들어서 DB 의 데이터를 보정하는 것이었습니다. Table 에 row 가 몇 억 건씩 들어있다보니 DBA 가 update 등으로 고치는걸 꺼리는 사내 문화 때문에 별도로 프로그램을 만들어서 몇 천건씩 읽어서 한 줄씩 update 하고, 그리고 몇 초 쉰 다음 다시 실행하는 형태로 개발되고 있었습니다. 그래서 이 때 처음으로 개선해보자는 마음으로 QueryDSL 을 사용했습니다. 접속해야 하는 DBMS 가 SQL Server 였기 때문이었습니다.

그런데, 생각보다 불편하더군요. 무엇보다 POJO(Bean) 을 PreparedStatement 의 Binding 할 값으로 넘겨주고 결과를 POJO 로 받아오는 단순한 기존 방식이 생각보다 불편했습니다. 그래서 QueryDSL 은 제 생각에서 빨리 지웠습니다.

이후 MySQL 으로 개발되는 시스템을 새로 만들면서 JOOQ 을 사용했습니다. 이 시스템은 매우 단순한 시스템이라서 DB 에 질의할 것이 10 여개 정도로 매우 적었습니다. 그래서 안성맞춤이었습니다.


결론적으로 직접 Query 을 작성하는게 빠른 저 같은 사용자에게는 여전히 불편하지만, 같이 일한 2 년차 개발자에게는 오타로 인한 오류를 줄여줄 수 있는 하나의 방법을 제시한 것이 되었고, 앞으로도 계속 써볼 생각입니다.

JPA 와 가장 다른 점은, JPA 은 시작할 때 DBMS 에 접속하여 DB Object 와 Java Object 간의 일치여부를 확인하는데 반해(이것 또한 제가 매우 싫어하는 부분, 코드 수정 후 10 초 이상 서버 기동해야 하는 경우에 정말 뚜껑 열리는 줄 알았어요) JOOQ 나 QueryDSL 같은 경우에는 미리 DBMS 에 접속하여 DB Object 을 분석하여 Java Code 을 생성해두고, 실제 Query 을 실행할 때 Query 을 생성하여 DBMS 에 질의를 보낸다는 것입니다. 그렇기 때문에 프로그램 시작 시 Delay 는 거의 차이가 없고, 단 한 번의 Java Code 생성으로 DB 변경 전까지 계속 사용할 수 있고, 생성되는 Code 을 어디에 두느냐에 따라 여러 작업자가 한 번 생성된 Java Code 을 재사용 할 수도 있습니다.


여전히 Spring Boot 에서 MyBatis 설정이 매우 간단하기 때문에 앞으로도 대세는 MyBatis 가 될 것 같지만, JPA 도입 대신 JOOQ 도입도 한 번 검토해보는 것을 추천드립니다.


2019/02/28 - [Programming/JOOQ] - [JOOQ-01] JOOQ 맛보기

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함