Java
jOOQ
JavaDay 24

jOOQ: DBにSQLライクにアクセスするライブラリの紹介

More than 3 years have passed since last update.


jOOQ


本記事では、jOOQというORマッパーについて紹介します。

 (sql)

SELECT * FROM BOOK
WHERE BOOK.PUBLISHED_IN = 2011
ORDER BY BOOK.TITLE

 (jOOQ)

create.selectFrom(BOOK)
.where(BOOK.PUBLISHED_IN).eq(2011)
.orderBy(BOOK.TITLE)

早速ですが、jOOQを利用すると上記のようにselect文が記述できます。

SQLに近いインタフェースで記述できるORマッパーになっています。


特徴


  • Database first: jOOQはデータベースファース(SQLを中心にしたアプローチをとってます)

  • Typesafe SQL: Javaのコンパイラを利用して、SQLのシンタックスをチェックしています

  • Code Generation: jOOQはデータベースのメタデータから自動生成を行います。

  • Active Record: jOOQはCRUDとPojoマッピングをアクティブ・レコードとして提供しています。

  • Multi-Tenancy: jOOQはテーブル名の変更などの環境変化にも容易に対応できます。


対応データベース

jOOQは4種類のパターンで提供されています。

種類によって、対応するDBの種類が異なっています。

ちなみにOSS版では下記のDBに対応しているとのことです。


  • CUBRID 8.4

  • Derby 10.10

  • Firebird 2.5

  • H2 1.3

  • HSQLDB 2.2

  • MariaDB 5.2

  • MySQL 5.5

  • PostgreSQL 9.0

  • SQLite


jOOQチュートリアルを実際にやっていきます(本家マニュアルを参考)


チュートリアルの実行環境


  • DB Server: 5.6.27 - MySQL Community Server

  • Fedora 23 (on Virtual Box)

  • Eclipse Mars.1


事前準備

jOOQは既存のテーブルをもとにアクセス可能なモデルを自動生成します。


1.DBの構築

MySQL上で事前にテーブルを作っておきます。



CREATE DATABASE `library`;

USE `library`;

CREATE TABLE `author` (

`id` int NOT NULL,

`first_name` varchar(255) DEFAULT NULL,

`last_name` varchar(255) DEFAULT NULL,

PRIMARY KEY (`id`)

);

--後でデータベースへのアクセスする際にセレクトするので、データも挿入しておきます。

INSERT INTO `author` VALUES(1,'jooq','skywalker');


2. DBの情報をもとにDBにアクセスするためのモデルを作成

一番簡単な方法は、jarファイルから生成する方法ということなので、

私もその方法で生成していきます。

今回の私の作業ディレクトリは以下のように構成しました。

workingDir


  • jooq-3.7.2.jar

  • jooq-codegen-3.7.2.jar

  • jooq-codegen-maven-3.7.2.jar

  • jooq-meta-3.7.2.jar

  • jooq-meta-extensions-3.7.2.jar

  • library.xml (DBの接続情報、出力先を記述したxmlファイル)

(具体的な作業)

本家URLからjOOQの各種ファイルをダウンロードしてきて、

jOOQ-lib/ 以下にある各種jarファイルを自分の作業用のディレクトリにコピーします。

またlibrary.xml(名前は任意のもの)に関しては、自分のDBの情報を記述する必要があるため修正します。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.7.0.xsd">
<!-- mysqlの情報は自分の環境に合わせて修正する必要があります -->
<jdbc>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost:3306/library</url>
<user>root</user>
<password></password>
</jdbc>
<generator>
<!-- The default code generator. You can override this one, to generate your own code style.
Supported generators:
- org.jooq.util.JavaGenerator
- org.jooq.util.ScalaGenerator
Defaults to org.jooq.util.JavaGenerator -->
<name>org.jooq.util.JavaGenerator</name>
<database>
<!-- The database type. The format here is:
org.util.[database].[database]Database -->
<name>org.jooq.util.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>library</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 -->
<excludes></excludes>
</database>
<target>
<!-- The destination package of your generated classes (within the destination directory) -->
<packageName>test.generated</packageName>
<!-- The destination directory of your generated classes -->
<!--自動生成したコードの保存先-->
<directory>/home/otokunaga/workspace/MySQLTest/src</directory>
</target>
</generator>
</configuration>


3.DBのためのモデルの自動生成

次のコマンドを実行してモデルを構築します。



java -classpath jooq-3.7.2.jar:jooq-meta-3.7.2.jar:jooq-codegen-3.7.2.jar:mysql-connector-java-5.1.18-bin.jar:. org.jooq.util.GenerationTool library.xml



各自利用しているjooqのバージョン,mysql-connectorのバージョンはそれぞれ読み替えてください。

↑のコマンドが無事に実行できたら、xmlで指定した保存先に、自動生成されたコードが保存されます。

実際には、次のようなコードが生成されます。


import java.util.Arrays;
import java.util.List;

import javax.annotation.Generated;

import org.jooq.Field;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.impl.TableImpl;

import src.test.generated.Keys;
import src.test.generated.Library;
import src.test.generated.tables.records.AuthorRecord;

/**
* This class is generated by jOOQ.
*/
@Generated(
value = {
"http://www.jooq.org",
"jOOQ version:3.7.2"
},
comments = "This class is generated by jOOQ"
)
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class Author extends TableImpl<AuthorRecord> {

private static final long serialVersionUID = -2070865002;

/**
* The reference instance of <code>library.author</code>
*/
public static final Author AUTHOR = new Author();

/**
* The class holding records for this type
*/
@Override
public Class<AuthorRecord> getRecordType() {
return AuthorRecord.class;
}

/**
* The column <code>library.author.id</code>.
*/
public final TableField<AuthorRecord, Integer> ID = createField("id", org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, "");

/**
* The column <code>library.author.first_name</code>.
*/
public final TableField<AuthorRecord, String> FIRST_NAME = createField("first_name", org.jooq.impl.SQLDataType.VARCHAR.length(255), this, "");

/**
* The column <code>library.author.last_name</code>.
*/
public final TableField<AuthorRecord, String> LAST_NAME = createField("last_name", org.jooq.impl.SQLDataType.VARCHAR.length(255), this, "");

/**
* Create a <code>library.author</code> table reference
*/
public Author() {
this("author", null);
}

/**
* Create an aliased <code>library.author</code> table reference
*/
public Author(String alias) {
this(alias, AUTHOR);
}

private Author(String alias, Table<AuthorRecord> aliased) {
this(alias, aliased, null);
}

private Author(String alias, Table<AuthorRecord> aliased, Field<?>[] parameters) {
super(alias, Library.LIBRARY, aliased, parameters, "");
}

/**
* {@inheritDoc}
*/
@Override
public UniqueKey<AuthorRecord> getPrimaryKey() {
return Keys.KEY_AUTHOR_PRIMARY;
}

/**
* {@inheritDoc}
*/
@Override
public List<UniqueKey<AuthorRecord>> getKeys() {
return Arrays.<UniqueKey<AuthorRecord>>asList(Keys.KEY_AUTHOR_PRIMARY);
}

/**
* {@inheritDoc}
*/
@Override
public Author as(String alias) {
return new Author(alias, this);
}

/**
* Rename this table
*/
public Author rename(String name) {
return new Author(name, null);
}
}


4. DBにアクセス

3.で生成したモデルを利用して、DBへアクセスしてみます。

なお、実際にeclipse上で動作させる場合には、ソースコードの自動生成に利用したjarファイルをビルドパスに設定しました。

今回は、mavenを利用していなかったため、ビルドパスなどは手動で通しました。

package test;

import java.sql.DriverManager;
import java.sql.SQLException;

import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

import com.mysql.jdbc.Connection;

import src.test.generated.tables.Author;

public class Main {

public static void main(String[] args) throws ClassNotFoundException {
String userName = "username";
String password = "password";
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/library";
try (Connection conn = (Connection) DriverManager.getConnection(url, userName, password)) {
DSLContext create = DSL.using(conn, SQLDialect.MYSQL);
Result<Record> result = create.select().from(Author.AUTHOR).fetch();
for (Record r : result) {
Integer id = r.getValue(Author.AUTHOR.ID);
String firstName = r.getValue(Author.AUTHOR.FIRST_NAME);
String lastName = r.getValue(Author.AUTHOR.LAST_NAME);
System.out.println("ID: " + id + "first name: " + firstName + "last name:" + lastName);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

これで、最初に挿入されたデータにアクセスできれば、成功です。


さいごに

今回, jOOQに関する概要からチュートリアルまで実施させてもらいました。

使用してみた個人的な感想としては、まずSQLライクに書けることが嬉しいこと、

マニュアルが丁寧なので、下手につまることがなく安定して利用できそうという感想を持ちました。

是非、DBアクセスはやっぱりSQL書きたい人は、一度試してもらうと面白いかもしれません。


参考にさせて頂いたサイト