티스토리 뷰
이번 프로젝트에서 jooq 을 이용해서 개발하면서 불편한 점이 몇 가지 있었습니다.
먼저, 객체(POJO)에 값을 넣고 돌아다니다가 DB 에 저장할 때 쿼리가 길어지는 문제였습니다.
public long insert(ChatInfo chatInfo) { return this.dsl .insertInto(CHAT_INFO, CHAT_INFO.SESSION_ID, CHAT_INFO.IS_END, CHAT_INFO.DATE_ADD, CHAT_INFO.DATE_MOD) .values(chatInfo.getSessionId(), "N", Timestamp.valueOf(LocalDateTime.now()), Timestamp.valueOf(LocalDateTime.now())) .returning(CHAT_INFO.INFO_SEQ) .fetchOne() .getInfoSeq(); }
대충 이런 식인데...실제로는 Table 에 컬럼이 십여개가 있다보니 꽤나 문장이 길어지는 문제가 있었습니다.
참고로, 위 쿼리는 info_seq 라는 자동증가값이 있는 테이블에 데이터를 저장하고 자동 발급된 info_seq 을 가져오는 구문입니다.
다른 일이 바빠 한동안은 이렇게 구현했습니다. update 도 말입니다. 물론 일부 컬럼만 수정할 경우에는 구문이 짧아지지만, 전체를 select 해와서 다시 update 하는 문장은 길어질 수 밖에 없었고(ORM 스럽게 해보려고 한걸까요?) 컬럼이 추가되거나 제거됐을 경우 문제가 됐습니다. 특히 제거됐을 때에는 어쨌든 런타임 시 오류가 발생하지만 추가됐을 경우에는 값이 변경이 안되니 알아채기 힘들어지는 문제가 있었습니다. 심지어 code-gen 을 maven 에서 package 생성할 때 자동실행되는 것을 꺼놨기 때문에 더욱 문제가 컸습니다.
그래서 정말 이렇게만 넣어야 하는건지 좀 더 뒤져봤습니다. 물론 그럴 리가 없지요...
https://www.jooq.org/doc/3.0/manual/sql-execution/fetching/pojos/
위 링크에서 해답을 얻었습니다. "Loading POJOs back into Records to store them" 섹션에서 말입니다.
핵심은 newRecord() 로 입력할 레코드(Table 의 한 줄)를 POJO 로 생성한 뒤 해당 레코드를 store() 로 저장하면 된다는 것입니다. newRecord() 에는 여러 매개변수가 올 수 있지만, 테이블의 형태와 POJO 객체를 매개변수로 넣는 형태가 가장 일반적이지 않을까 싶습니다.
단, DB 의 default 을 적용시키는데 문제가 좀 있어서(망할 MySQL 5.5) 아래와 같이 현재날짜는 추가로 입력을 해주었습니다.
public long insert(ChatInfo chatInfo) { ChatInfoRecord chatInfoRecord = this.dsl.newRecord(CHAT_INFO, chatInfo); chatInfoRecord.setDateAdd(LocalDateTime.now()); chatInfoRecord.setDateMod(LocalDateTime.now()); // 레코드 저장 후 적용이 되지 않았을 경우 Exception 발생 if (chatInfoRecord.store() < 1) throw new Exception("DB 저장 오류"); return chatInfoRecord.getInfoSeq(); }
이렇게 POJO 을 이용해 DB 입력을 할 경우 컬럼 수가 많아질 경우 코드가 매우 짧아질 수 있습니다. 그리고 store() 을 호출하여 저장했을 때 record 객체에 자동증가값(PK 이기도 합니다)이 채워져서 바로 이용도 가능합니다.
DB 수정(갱신, update)의 경우는 조금 다른데, store() 는 순전히 입력을 위한 것이라 수정 시 사용하면 중복된 PK 와 관련된 오류가 발생합니다. 그래서 다음과 같이 처리해야 합니다.
public int update(ChatInfo chatInfo) { ChatInfoRecord chatInfoRecord = this.dsl.newRecord(CHAT_INFO, chatInfo); chatInfoRecord.setDateMod(LocalDateTime.now()); // 레코드 저장 int result = this.dsl.executeUpdate(chatInfoRecord); if (result < 0) throw new Exception("DB 수정 오류"); return result; }
executeUpdate() 을 이용해 record 을 전달하여 저장하는 형태가 됩니다.
그런데, API 문서를 봤거나 IDE 을 이용해 어떤 메서드가 있는지 확인해봤다면 executeInsert() 도 있다는 것을 알 수 있는데, 왜 굳이 store() 을 썼을까요?
버그일지 의도된 것인지 현재로썬 알 수 없지만, executeInsert() 로 입력했을 때 자동증가값이 record 에 갱신되지 않았기 때문입니다(이 글을 쓰는 시점에서 3.11 Community 버전을 이용했습니다). 그래서 수정 시 다른 방식으로 저장했지만, 그렇게 이질적이진 않아서 크게 문제는 없을 것으로 생각됩니다. 물론 executeDelete() 도 존재하는데, 이걸 이용해서 삭제할 일이 많지는 않을 것으로 판단됩니다.
단순 POJO 을 이용해서 저장하는 방법에 대해서 기술해보았습니다. 더 편한 방식도 존재하는데, 이 부분은 다음 글에서...
'Programming > JOOQ' 카테고리의 다른 글
[JOOQ-04] 좀 더 복잡한 질의 실행해보기 (0) | 2019.03.05 |
---|---|
[JOOQ-03] 테스트 DB 을 생성하고 JOOQ 객체 생성하기 (0) | 2019.03.05 |
[JOOQ-02] JOOQ 에 대해서 좀 더 알아보기 (0) | 2019.03.01 |
[JOOQ-01] JOOQ 맛보기 (0) | 2019.02.28 |
[프롤로그] JOOQ 을 사용하게 된 계기 (0) | 2019.02.28 |
- Total
- Today
- Yesterday
- 페이징
- java config
- 워드프레스
- Redmine
- Spring
- NoSQL
- manjaro
- 외장 WAS
- RestTemplate
- 클라우드플레어
- Nas
- SI
- OracleJDK
- git
- jooq
- 프로젝트 규모
- proxmox
- Spring MVC
- Spring Boot
- 시니어 프로그래머
- paging
- 내장 WAS
- 도입기
- boot
- couchbase
- docker
- KDE
- Phabricator
- 엘지
- messages.properties
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |