티스토리 뷰

반응형

이번 프로젝트에서 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 을 이용해서 저장하는 방법에 대해서 기술해보았습니다. 더 편한 방식도 존재하는데, 이 부분은 다음 글에서...

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
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
글 보관함