티스토리 뷰
2019/02/28 - [Programming/JOOQ] - [프롤로그] JOOQ 을 사용하게 된 계기
JOOQ 을 어떻게 사용하는건지 아주 간단한 맛보기 프로그램을 만들어보겠습니다.
PC 에 docker 을 사용할 수 있는 환경을 구축한 후 MySQL 8 을 설치하였습니다. jooq 라는 계정을 만들고 jooq@1234 라는 패스워드를 생성하고 jooq 라는 schema(DB) 을 생성하였습니다. 이 모든 설정은 MySQL 와 관련된 것이기 때문에 생략하겠습니다.
생성된 DB 에 다음과 같이 테스트용 테이블 하나와 두 개의 데이터를 입력하였습니다.
CREATE TABLE `jooq`.`jooq_board` ( `seq` INT NOT NULL AUTO_INCREMENT, `author` VARCHAR(100) NOT NULL, `content` TEXT NOT NULL, `read_cnt` VARCHAR(45) NULL, `add_date` DATETIME NOT NULL DEFAULT now(), `mod_date` DATETIME NOT NULL DEFAULT now(), PRIMARY KEY (`seq`)); INSERT INTO `jooq`.`jooq_board` (`author`, `content`, `read_cnt`) VALUES ('zepinos', '테스트', '0'); INSERT INTO `jooq`.`jooq_board` (`author`, `content`, `read_cnt`) VALUES ('okky', '오키사이트\nhttps://okky.kr', '0');
그리고, IDE 에서 Spring Boot 프로젝트를 하나 생성했습니다. 만약 IDE 을 사용하지 않는다면 웹사이트에서 직접 생성해도 되고, maven 구조에 맞게 직접 생성해도 됩니다.
생성할 때 Java 11, maven, war 환경에 DevTools, Lombok, Web, MySQL, JOOQ 을 선택하였습니다. 그리고, 이를 바탕으로 만들어진 pom.xml 에 tomcat 을 제외시키고 undertow 을 추가하였습니다.
아래와 같은 pom.xml 이 생성되었습니다.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zepinos.blog</groupId> <artifactId>jooq</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>jooq</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jooq</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
그리고 DB 접속 정보 설정을 위해 src/main/resources 의 application.properties 파일을 application.yml 로 확장자를 변경하고 아래와 같이 내용을 추가하였습니다. 개인적으로 YAML 을 Properties 보다 선호합니다.
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/jooq?useSSL=false username: jooq password: jooq@1234 jooq: sql-dialect: mysql_8_0
그리고 src/main/java 에 MVC 환경에 맞게 controller, service, dao 패키지(Package)를 추가하였습니다. 각 패키지에는 다음과 같은 내용을 추가하였습니다.
controller/JooqBoardController.java
package com.zepinos.blog.jooq.controller; import com.zepinos.blog.jooq.service.JooqBoardService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; @RestController @RequestMapping("/jooq_board") public class JooqBoardController { private final JooqBoardService jooqBoardService; @Autowired public JooqBoardController(JooqBoardService jooqBoardService) { this.jooqBoardService = jooqBoardService; } @GetMapping("/list") public Callable<Map<String, Object>> list() { Map<String, Object> result = new HashMap<>(); result.put("list", jooqBoardService.list()); return () -> result; } }
service/JooqBoardService.java
package com.zepinos.blog.jooq.service; import com.zepinos.blog.jooq.dao.JooqBoardDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; @Service public class JooqBoardService { private final JooqBoardDao jooqBoardDao; @Autowired public JooqBoardService(JooqBoardDao jooqBoardDao) { this.jooqBoardDao = jooqBoardDao; } public List<Map<String, Object>> list() { return jooqBoardDao.list(); } }
dao/JooqBoardDao.java
package com.zepinos.blog.jooq.dao; import org.jooq.DSLContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.List; import java.util.Map; import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.table; @Repository public class JooqBoardDao { private final DSLContext dslContext; private final JdbcTemplate jdbcTemplate; @Autowired public JooqBoardDao(DSLContext dslContext, JdbcTemplate jdbcTemplate) { this.dslContext = dslContext; this.jdbcTemplate = jdbcTemplate; } public List<Map<String, Object>> list() { String sql = dslContext.select(field("jooq_board.seq"), field("jooq_board.author"), field("jooq_board.content"), field("jooq_board.read_cnt"), field("jooq_board.add_date"), field("jooq_board.mod_date")) .from(table("jooq_board")) .where(field("jooq_board.seq").greaterThan(0)) .limit(2) .offset(1) .getSQL(); System.out.println("sql : " + sql); return jdbcTemplate.queryForList(sql, 0, 2, 1); } }
설명이 필요한 코드는 역시 dao/JooqBoardDao.java 파일입니다.
프롤로그에서 설명했듯이, JOOQ 는 DB 에 접속하여 DB Object 을 분석하여 Java Code 을 생성합니다. 그런데, 위에서는 그런 작업을 전혀 진행하지 않았습니다. JOOQ 는 DSL 형태로 질의를 작성하면 sql-dialect (JPA 써보신 분들은 아시겠지만, dialect 을 방언이라고 직역해서 쓰시더군요) 설정에 따라 DBMS 문법에 맞게 결과를 만들어내는 라이브러리입니다. 그래서, 위와 같이 field() 나 table() 을 이용해 생성된 코드 없이도 직접 질의를 만들어낼 수도 있게 되어 있습니다. 그 결과를 String 으로 저장할 수 있으며, where() 에서 greaterThan() 와 같이 parameter 로 입력할 수 있는 부분은 PreparedStatement 에 맞게 ? 로 변환되어 제공됩니다.
그래서, 이렇게 생성된 질의는 기존의 방식을 이용해서(여기서는 JdbcTemplate) 질의를 실행할 수 있습니다. 위에서는 greaterThan, limit, offset 세 개의 paramter 을 이용하고 있기 때문에 질의와 함께 세 개의 매개변수를 추가로 지정해서 실행할 수 있도록 했습니다.
이렇게 작성된 프로그램을 실행하고 웹브라우져로 http://localhost:8080/jooq_board/list 에 접속하면 웹브라우져와 콘솔에서 다음과 같은 결과를 확인할 수 있습니다.
물론 logging 을 활성화하지 않아서 소스에 추가한 출력만 표시됩니다만, MySQL 8 에 적합한 쿼리를 JOOQ 가 생성한다는 것을 알 수 있습니다.
그렇다면, 이 프로그램을 Cubrid 에서 실행한다면 어떻게 될까요? 제가 Cubrid 을 써본 적도 없고, 굳이 Docker 로 내려 받아 확인할 필요도 없이, sql-dialect 을 cubrid 로만 변경해도 원하는 바를 확인할 수 있습니다.
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/jooq?useSSL=false username: jooq password: jooq@1234 jooq: sql-dialect: cubrid
실행한 뒤 브라우져로 접근하면 오류가 발생하지만, 콘솔에서 다음과 같이 Cubrid 에 맞는 쿼리가 자동 생성됨을 확인할 수 있습니다.
실제 JOOQ 가 만들어낸 질의는 아래와 같습니다.
select jooq_board.seq, jooq_board.author, jooq_board.content, jooq_board.read_cnt, jooq_board.add_date, jooq_board.mod_date from jooq_board where jooq_board.seq > cast(? as int) limit ?, ?
limit 가 아닌 다른 부분에서 더 극적인 차이를 느낄 수 있겠지만, 어쨌든 이러한 질의 생성은 이미 JPA 을 통해서 경험해보신 분들도 많으실 겁니다. 그렇기 때문에 이 정도 선에서 설명을 줄이겠습니다.
다음 글부터는 JOOQ 공식문서의 순서대로 JOOQ 을 소개해나갈 계획입니다. 예제 DB 도 공식문서의 것을 이용할 것이구요. 많은 관심 부탁드립니다.
2019/03/01 - [Programming/JOOQ] - [JOOQ-02] JOOQ 에 대해서 좀 더 알아보기
'Programming > JOOQ' 카테고리의 다른 글
[JOOQ-04] 좀 더 복잡한 질의 실행해보기 (0) | 2019.03.05 |
---|---|
[JOOQ-03] 테스트 DB 을 생성하고 JOOQ 객체 생성하기 (0) | 2019.03.05 |
[JOOQ-02] JOOQ 에 대해서 좀 더 알아보기 (0) | 2019.03.01 |
[프롤로그] JOOQ 을 사용하게 된 계기 (0) | 2019.02.28 |
JOOQ 에서 POJO 을 이용해 입력/수정을 해보자 (0) | 2018.12.18 |
- Total
- Today
- Yesterday
- Spring Boot
- Spring MVC
- 프로젝트 규모
- OracleJDK
- jooq
- couchbase
- paging
- docker
- proxmox
- 워드프레스
- Phabricator
- 엘지
- 내장 WAS
- git
- 클라우드플레어
- Spring
- 페이징
- SI
- NoSQL
- manjaro
- 도입기
- messages.properties
- Nas
- 시니어 프로그래머
- boot
- 외장 WAS
- RestTemplate
- KDE
- java config
- Redmine
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |