zepinos
18k
2019-03-08 12:19:22 작성 2019-03-08 16:20:44 수정됨
5
548

[펌][JOOQ-03] 테스트 DB 을 생성하고 JOOQ 객체 생성하기


출처: https://zepinos.tistory.com/55 [zepinos BLOG]





앞선 글에서 아주 간단한 테스트를 위해 하나의 Table 을 생성하고 JOOQ 객체 생성 없이 사용하는 예제를 만들어봤습니다. 하지만, JOOQ 객체 없이 JOOQ 을 쓴다는건 생각하기 힘든 일입니다. 왜냐하면, String 으로 된 "board.seq" 와 같은 것으로 오타 방지 등을 할 수 없기 때문입니다.

반대로 JPA 와 달리 사용자가 POJO 을 만들고 이를 바탕으로 DB 을 자동으로 생성해주는 것 또한 바람직하지 않다고 생각합니다. ORM 을 많이 사용하게 되면서 Java Object(POJO) 을 기반으로 데이터 구조를 설계하는 문화도 꽤나 정착되었지만, 여전히 기획을 바탕으로 데이터 구조를 설계할 때에는 ER Diagram 을 가장 많이 사용하고 있기 때문입니다. 그리고, Forward Engineering 을 통해 RDBMS 에 DB 을 자동 생성하고, 수정된 구조를 자동 반영하는 경우가 보편적입니다.


여기서는 JOOQ 공식 문서의 예제를 생성해보려고 합니다. 문서에서는 Oracle 으로 된 DDL, DML 이 제공되지만, MySQL 으로 예제를 만들 것이기 때문에 아래와 같이 MySQL 에 맞는 질의로 바꾸었습니다.


CREATE TABLE `language` (
  `id` INT NOT NULL,
  `cd` CHAR(2) NOT NULL,
  `description` VARCHAR(50) NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `author` (
  `id` INT NOT NULL,
  `first_name` VARCHAR(50) NULL,
  `last_name` VARCHAR(50) NOT NULL,
  `date_of_birth` DATE NULL,
  `year_of_birth` INT(4) NULL,
  `distinguished` INT(1) NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `book` (
  `id` INT NOT NULL,
  `author_id` INT NOT NULL,
  `title` VARCHAR(400) NOT NULL,
  `published_in` INT NOT NULL,
  `language_id` INT NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `fk_book_author_idx` (`author_id` ASC),
  INDEX `fk_book_language_idx` (`language_id` ASC),
  CONSTRAINT `fk_book_author`
    FOREIGN KEY (`author_id`)
    REFERENCES `author` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_book_language`
    FOREIGN KEY (`language_id`)
    REFERENCES `language` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION
);

CREATE TABLE `book_store` (
  `name` VARCHAR(400) NOT NULL,
  UNIQUE INDEX `name_UNIQUE` (`name` ASC)
);


CREATE TABLE `book_to_book_store` (
  `name` VARCHAR(400) NOT NULL,
  `book_id` INT NOT NULL,
  `stock` INT NULL,
  PRIMARY KEY (`name`, `book_id`),
  INDEX `fk_b2bs_book_idx` (`book_id` ASC),
  CONSTRAINT `fk_b2bs_book_store`
    FOREIGN KEY (`name`)
    REFERENCES `book_store` (`name`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_b2bs_book`
    FOREIGN KEY (`book_id`)
    REFERENCES `book` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION
);


INSERT INTO `language` (`id`, `cd`, `description`) VALUES ('1', 'en', 'English');
INSERT INTO `language` (`id`, `cd`, `description`) VALUES ('2', 'de', 'Deutsch');
INSERT INTO `language` (`id`, `cd`, `description`) VALUES ('3', 'fr', 'Français');
INSERT INTO `language` (`id`, `cd`, `description`) VALUES ('4', 'pt', 'Português');

INSERT INTO `author` (`id`, `first_name`, `last_name`, `date_of_birth`, `year_of_birth`) VALUES ('1', 'George', 'Orwell', '1903-06-26', '1903');
INSERT INTO `author` (`id`, `first_name`, `last_name`, `date_of_birth`, `year_of_birth`) VALUES ('2', 'Paulo', 'Coelho', '1947-08-24', '1947');

INSERT INTO `book` (`id`, `author_id`, `title`, `published_in`, `language_id`) VALUES ('1', '1', '1984', '1948', '1');
INSERT INTO `book` (`id`, `author_id`, `title`, `published_in`, `language_id`) VALUES ('2', '1', 'Animal Farm', '1945', '1');
INSERT INTO `book` (`id`, `author_id`, `title`, `published_in`, `language_id`) VALUES ('3', '2', 'O Alquimista', '1988', '4');
INSERT INTO `book` (`id`, `author_id`, `title`, `published_in`, `language_id`) VALUES ('4', '2', 'Brida', '1990', '2');

INSERT INTO `book_store` (`name`) VALUES ('Orell Füssli');
INSERT INTO `book_store` (`name`) VALUES ('Ex Libris');
INSERT INTO `book_store` (`name`) VALUES ('Buchhandlung im Volkshaus');

INSERT INTO `book_to_book_store` (`name`, `book_id`, `stock`) VALUES ('Orell Füssli', '1', '10');
INSERT INTO `book_to_book_store` (`name`, `book_id`, `stock`) VALUES ('Orell Füssli', '2', '10');
INSERT INTO `book_to_book_store` (`name`, `book_id`, `stock`) VALUES ('Orell Füssli', '3', '10');
INSERT INTO `book_to_book_store` (`name`, `book_id`, `stock`) VALUES ('Ex Libris', '1', '1');
INSERT INTO `book_to_book_store` (`name`, `book_id`, `stock`) VALUES ('Ex Libris', '3', '2');
INSERT INTO `book_to_book_store` (`name`, `book_id`, `stock`) VALUES ('Buchhandlung im Volkshaus', '3', '1');


이렇게 생성된 DB 을 아래와 같이 질의할 수 있도록 만드는게 첫번째 목표입니다.


Result<Record3<String, String, String>> result =
create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
      .from(BOOK)
      .join(AUTHOR)
      .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
      .where(BOOK.PUBLISHED_IN.eq(1948))
      .fetch();


이제 JOOQ Object 을 생성하기 위해 아래와 같은 XML 파일을 생성합니다. 수동으로 생성하기 위한 정보를 기입하는데, 접속정보와 접속할 DB(Schema), 포함시킬 객체와 제외할 객체를 명시할 수 있습니다. 그리고 파일을 저장할 위치와, Java 에서 사용할 Package 정보도 기입할 수 있습니다. 코드 중간의 주석을 보면 바로 눈치챌 수 있지만, JVM 을 사용하는 다른 언어인 Scala 도 지원합니다. 물론 Groovy 나 Kotlin 에서도 일부 주의할 사항만 유념한다면 사용하는데 문제가 없다고 합니다.


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.11.0.xsd">
  <!-- Configure the database connection here -->
  <jdbc>
    <driver>com.mysql.jdbc.Driver</driver>
    <url>jdbc:mysql://localhost:3306/jooq</url>
    <user>jooq</user>
    <password>jooq@1234</password>
  </jdbc>

  <generator>
    <!-- The default code generator. You can override this one, to generate your own code style.
         Supported generators:
         - org.jooq.codegen.JavaGenerator
         - org.jooq.codegen.ScalaGenerator
         Defaults to org.jooq.codegen.JavaGenerator -->
    <name>org.jooq.codegen.JavaGenerator</name>

    <database>
      <!-- The database type. The format here is:
           org.jooq.meta.[database].[database]Database -->
      <name>org.jooq.meta.mysql.MySQLDatabase</name>

      <!-- The database schema (or in the absence of schema support, in your RDBMS this
           can be the owner, user, database name) to be generated -->
      <inputSchema>jooq</inputSchema>

      <!-- All elements that are generated from your schema
           (A Java regular expression. Use the pipe to separate several expressions)
           Watch out for case-sensitivity. Depending on your database, this might be important! -->
      <includes>.*</includes>

      <!-- All elements that are excluded from your schema
           (A Java regular expression. Use the pipe to separate several expressions).
           Excludes match before includes, i.e. excludes have a higher priority -->
      <excludes></excludes>
    </database>

    <target>
      <!-- The destination package of your generated classes (within the destination directory) -->
      <packageName>com.zepinos.blog.jooq.generated</packageName>

      <!-- The destination directory of your generated classes. Using Maven directory layout here -->
      <directory>C:/temp/src/main/java</directory>
    </target>
  </generator>
</configuration>


위와 같은 내용으로 jooq.xml 파일을 생성해보겠습니다. 그리고 아래와 같이 java 명령으로 JOOQ Object 을 생성할 수 있습니다. 아래 코드는 Widnows 용 실행코드이고, *NIX 에서는 세미콜론(;) 대신에 콜론(:)으로 jar 파일 위치를 연결해주면 됩니다.


java -classpath jooq-3.11.9.jar;jooq-meta-3.11.9.jar;jooq-codegen-3.11.9.jar;mysql-connector-java-8.0.15.jar;. org.jooq.codegen.GenerationTool jooq.xml


이 명령을 실행하기 위해서는 선언된 jar 파일을 따로 준비해야 합니다. 그래서 실제로 이렇게 생성하는 것보다는 maven 을 이용해서 생성하는 것을 추천드립니다. 만약 Java 9 이상으로 실행한다면 다음과 같이 추가적인 library 가 필요합니다. 그래서 추후에는 maven 을 이용해서 자동 생성하는 것을 권해드립니다.


java -classpath jooq-3.11.9.jar;jooq-meta-3.11.9.jar;jooq-codegen-3.11.9.jar;mysql-connector-java-8.0.15.jar;jaxb-api-2.4.0-b180830.0359.jar;jaxb-runtime-2.4.0-b180830.0438.jar;jaxws-api-2.3.1.jar;istack-commons-runtime-3.0.8.jar;javax.activation-1.2.0.jar;. org.jooq.codegen.GenerationTool jooq.xml


위와 같이 실행하면 다음과 같은 형태의 로그가 출력되면서 지정한 위치에 파일들이 생성되는 것을 확인할 수 있습니다.


3월 05, 2019 9:11:09 오전 org.jooq.tools.JooqLogger info

정보: Initialising properties  : jooq.xml

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: No &lt;inputCatalog/&gt; was provided. Generating ALL available catalogs instead.

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: License parameters

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   Thank you for using jOOQ and jOOQ's code generator

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Database parameters

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   dialect                : MYSQL

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   URL                    : jdbc:mysql://localhost:3306/jooq?useSSL=false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   target dir             : C:/temp/src/main/java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   target package         : com.zepinos.blog.jooq.generated

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   includes               : [.*]

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   excludes               : []

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   includeExcludeColumns  : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: JavaGenerator parameters

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   annotations (generated): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   annotations (JPA: any) : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   annotations (JPA: version):

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   annotations (validation): false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments               : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on attributes : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on catalogs   : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on columns    : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on keys       : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on links      : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on packages   : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on parameters : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on queues     : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on routines   : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on schemas    : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on sequences  : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on tables     : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   comments on udts       : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   daos                   : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   deprecated code        : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (any): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (catalogs): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (keys): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (links): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (queues): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (routines): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (schemas): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (sequences): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (tables): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   global references (udts): true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   indexes                : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   instance fields        : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   interfaces             : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   interfaces (immutable) : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   javadoc                : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   keys                   : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   links                  : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   pojos                  : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   pojos (immutable)      : false

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   queues                 : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   records                : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   routines               : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   sequences              : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   table-valued functions : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   tables                 : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   udts                   : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:   relations              : true

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generation remarks

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating catalogs      : Total: 1

WARNING: An illegal reflective access operation has occurred

WARNING: Illegal reflective access by org.jooq.tools.reflect.Reflect (file:/D:/jooq-3.11.9.jar) to constructor java.lang.invoke.MethodHandles$Lookup(java.lang.Class)

WARNING: Please consider reporting this to the maintainers of org.jooq.tools.reflect.Reflect

WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations

WARNING: All illegal access operations will be denied in a future release

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:


@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@  @@        @@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@        @@@@@@@@@@

@@@@@@@@@@@@@@@@  @@  @@    @@@@@@@@@@

@@@@@@@@@@  @@@@  @@  @@    @@@@@@@@@@

@@@@@@@@@@        @@        @@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@        @@        @@@@@@@@@@

@@@@@@@@@@    @@  @@  @@@@  @@@@@@@@@@

@@@@@@@@@@    @@  @@  @@@@  @@@@@@@@@@

@@@@@@@@@@        @@  @  @  @@@@@@@@@@

@@@@@@@@@@        @@        @@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  Thank you for using jOOQ 3.11.9


3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ARRAYs fetched           : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Enums fetched            : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Packages fetched         : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Routines fetched         : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Tables fetched           : 5 (5 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: No schema version is applied for catalog . Regenerating.

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating catalog       : DefaultCatalog.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ==========================================================

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating schemata      : Total: 1

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: No schema version is applied for schema jooq. Regenerating.

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating schema        : Jooq.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: ----------------------------------------------------------

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Sequences fetched        : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: UDTs fetched             : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating tables

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Adding foreign key       : fk_b2bs_book (jooq.book_to_book_store.book_id) referencing KEY_book_PRIMARY

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Adding foreign key       : fk_b2bs_book_store (jooq.book_to_book_store.name) referencing KEY_book_store_name_UNIQUE

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Adding foreign key       : fk_book_author (jooq.book.author_id) referencing KEY_author_PRIMARY

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Adding foreign key       : fk_book_language (jooq.book.language_id) referencing KEY_language_PRIMARY

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Synthetic primary keys   : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Overriding primary keys  : 5 (0 included, 5 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table         : Author.java [input=author, output=author, pk=KEY_author_PRIMARY]

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Indexes fetched          : 8 (8 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table         : Book.java [input=book, output=book, pk=KEY_book_PRIMARY]

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table         : BookStore.java [input=book_store, output=book_store, pk=N/A]

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table         : BookToBookStore.java [input=book_to_book_store, output=book_to_book_store, pk=KEY_book_to_book_store_PRIMARY]

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table         : Language.java [input=language, output=language, pk=KEY_language_PRIMARY]

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Tables generated         : Total: 600.128ms

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table references

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Table refs generated     : Total: 604.653ms, +4.524ms

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating Keys

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Keys generated           : Total: 610.236ms, +5.583ms

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating Indexes

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Indexes generated        : Total: 614.807ms, +4.57ms

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating table records

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating record        : AuthorRecord.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating record        : BookRecord.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating record        : BookStoreRecord.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating record        : BookToBookStoreRecord.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generating record        : LanguageRecord.java

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Table records generated  : Total: 644.946ms, +30.139ms

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Domains fetched          : 0 (0 included, 0 excluded)

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Generation finished: jooq: Total: 647.514ms, +2.568ms

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보:

3월 05, 2019 9:11:10 오전 org.jooq.tools.JooqLogger info

정보: Removing excess files


이제  생성된 파일들을 소스에 병합한 뒤(경로를 소스 내로 잘 정의했다면 복사가 필요없지만) 기존의 field() 나 table() 대신에 아래와 같이 처리할 수 있는지 확인해보겠습니다.

기존의 JOOQ-01 소스에서 DAO 파일을 수정해서 아래와 같이 변경합니다.


package com.zepinos.blog.jooq.dao;

import org.jooq.DSLContext;
import org.jooq.Record3;
import org.jooq.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.zepinos.blog.jooq.generated.tables.Author.AUTHOR;
import static com.zepinos.blog.jooq.generated.tables.Book.BOOK;

@Repository
public class JooqBoardDao {

	private final DSLContext create;
	private final JdbcTemplate jdbcTemplate;

	@Autowired
	public JooqBoardDao(DSLContext create, JdbcTemplate jdbcTemplate) {
		this.create = create;
		this.jdbcTemplate = jdbcTemplate;
	}

	public List<Map<String, Object>> list() {

		Result<Record3<String, String, String>> result =
				create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
						.from(BOOK)
						.join(AUTHOR)
						.on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
						.where(BOOK.PUBLISHED_IN.eq(1948))
						.fetch();

		List<Map<String, Object>> list = new ArrayList<>();

		if (result.size() > 0) {

			for (Record3<String, String, String> record3 : result) {

				Map<String, Object> map = new HashMap<>();
				map.put("title", record3.getValue(BOOK.TITLE));
				map.put("firstName", record3.getValue(AUTHOR.FIRST_NAME));
				map.put("lastName", record3.getValue(AUTHOR.LAST_NAME));

				list.add(map);

			}

		}

		return list;

	}

}


결과는 아래와 같이 출력됩니다.



JOOQ 에서 직접 질의를 하여 결과를 받아온 뒤 다시 Java Object 로 변경하는 코드가 조금 지저분합니다. 물론 POJO 을 만들어서 바로 넣어줄 수도 있습니다. 그 부분은 다음에 다루도록 하겠습니다.

1
0
  • 댓글 5

  • ledboo
    58
    2019-04-08 00:32:41


    @Repository 붙인 클래스의 이름이 Dao 로 되어 있으니깐 좀 어색해 보이는데요..

    Repository 와 Dao 는 비슷하지만서도 특성이 좀 다른데.. Jooq 에서는 원래 이런식으로 네이밍을 하는 건가요? 



    @Repository
    public class JooqBoardDao 
    0
  • zepinos
    18k
    2019-04-08 09:24:44

    ledboo 님 // 아뇨. 제 마음대로 정한 겁니다. JOOQ 는 Query 을 생성하는 걸 도와주는 라이브러리이기 때문에 어느 위치에 있어도 상관 없습니다. @Component 을 상속받은 객체를 이용해서 주입받기 위해 @Component 을 사용할 수도 있지만, 저장소(RDBMS)와 연동된다는 걸 강조하기 위해 @Repository 을 쓴 것 뿐이라고 생각하셔도 됩니다.

    0
  • ledboo
    58
    2019-04-08 13:45:26
    @zepions 님 답변 주셔서 감사합니다.~^^
    0
  • 규다롱
    6
    2019-04-17 16:54:16

    형태가 SPRING DATA JPA의 Querydsl이랑 비슷하네요.

    0
  • zepinos
    18k
    2019-04-17 19:50:55

    규다롱 님 // 경쟁상대입니다 ^^;;;

    0
  • 로그인을 하시면 댓글을 등록할 수 있습니다.