Data GeekeryはjOOQのバージョン3.9.0をリリースした。これはオブジェクトリレーショナルマッピング(ORM)のJavaツールキットだ。型安全なクエリを使えるようにデータベースからコードを生成する。2010年8月に初めて導入された。このリリースでの新しい機能は次のようなものだ。
- 実験的なパーサー。
- 文字列のSQLをjOOQの構文ツリーに解析する。
- チェッカーフレームワークの統合。
- jOOQに型安全性をさらに加える。
- Oracle 12cとPL/SQLの連携への改善。
- Oracle 12cでの新しい機能をサポートする。
- JSR-310のJava Time API。
- 従来のJDBCの日付/時間の型とJSR-310のJava Time APIをサポートする単一のAPI。
オープンソースバージョンのjOOQは次のデータベースをサポートする。
- MySQL 5.5, 5.6, 5.7, 8.0
- PostgreSQL 9.3以降
- MariaDB 5.2以降
- CUBRID 8.4以降
- Apache Derby 10.10以降
- Firebird 2.5, 3.0
- H2 1.3, 1.4
- HSQLDB 2.2以降
- SQLite 3
さまざまなライセンスオプションはjOOQのライセンスページにある。
はじめの一歩
jOOQアプリケーションの作成を始めるに当たり、次のER図を考えてみよう。pubs
という出版データベースを作っている。
Mavenを使うなら、データベースドライバとjOOQコードジェネレータを依存に加える。
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen</artifactId>
<version>3.9.0</version>
</dependency>
</dependencies>
データベースのプロパティは<profile>
セクションに定義する。
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<jdbc.user>root</jdbc.user>
<jdbc.password></jdbc.password>
<jdbc.url>jdbc:mysql://localhost:3306/pubs</jdbc.url>
<jdbc.driver>com.mysql.cj.jdbc.Driver</jdbc.driver>
</properties>
</profile>
以下のプラグインはMavenのゴールであるgenerate
とjOOQコードジェネレータのプロパティを定義する。プロパティは<generate></generate>
タグに定義する。使用するデータベースとデータベーススキーマ、Javaコードの出力パッケージをここに含める。
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>3.9.0</version>
<!-- The plugin should hook into the generate goal -->
<executions>
<execution>
<goals>
= <goal>generate</goal>t;
</goals>
</execution>
</executions>
<configuration>
<jdbc>
<driver>${jdbc.driver}</driver>
<url>${jdbc.url}</url>
<user>${jdbc.user}</user>
<password>${jdbc.password}</password>
</jdbc>
<generator>
<database>
= <name>org.jooq.util.mysql.MySQLDatabase</name>t;
= <includes>.*</includes>t;
= <excludes></excludes>t;
= <inputSchema>pubs</inputSchema>t;
</database>
<target>
= <packageName>org.redlich.pubs.model</packageName>t;
= <directory>src/main/java</directory>t;
</target>
</generator>
</configuration>
</plugin>
pubs
データベースへのサンプルのSQLクエリはjOOQを使いモデルにする。
SELECT title,publish_date,authors.last_name,types.type,publishers.publisher
FROM publications
INNER JOIN authors ON authors.id = publications.author_id
INNER JOIN types ON types.id = publications.type_id
INNER JOIN publishers ON publishers.id = publications.publisher_id;
jOOQが生成したコードを使い、アプリケーションはデータベースにアクセスし型安全のクエリを書ける。
public class Application {
public static void main(String[] args) throws Exception {
String user = System.getProperty("jdbc.user");
String password = System.getProperty("jdbc.password");
String url = System.getProperty("jdbc.url");
String driver = System.getProperty("jdbc.driver");
Class.forName(driver).newInstance();
try(Connection connection = DriverManager.getConnection(url,user,password)) {
DSLContext dslContext = DSL.using(connection,SQLDialect.MYSQL);
Result<Record> result = dslContext.select()
.from(PUBLICATIONS)
.join(AUTHORS)
.on(AUTHORS.ID.equal(PUBLICATIONS.AUTHOR_ID))
.join(TYPES)
.on(TYPES.ID.equal(PUBLICATIONS.TYPE_ID))
.join(PUBLISHERS)
.on(PUBLISHERS.ID.equal(PUBLICATIONS.PUBLISHER_ID))
.fetch();
for(Record record : result) {
Long id = record.getValue(PUBLICATIONS.ID);
String title = record.getValue(PUBLICATIONS.TITLE);
Long authorID = record.getValue(PUBLICATIONS.AUTHOR_ID);
String lastName = record.getValue(AUTHORS.LAST_NAME);
String firstName = record.getValue(AUTHORS.FIRST_NAME);
String type = record.getValue(TYPES.TYPE);
String publisher = record.getValue(PUBLISHERS.PUBLISHER);
Date publishDate = record.getValue(PUBLICATIONS.PUBLISH_DATE);
}
}
catch(Exception exception) {
exception.printStackTrace();
}
}
}
jOOQが生成したテーブルとフィールド名は大文字となることに注意してほしい。jOOQプロジェクト全体はGitHubにある。
Lukas Eder氏は、Data Geekery GmbHの創業者でCEOだが、InfoQにjOOQのこの最新リリースについて語った。
InfoQ「Data Geekeryでの現在のあなたの役割は何ですか?」
Eder「私はData Geekeryの創業者でCEOです。Data GeekeryはjOOQを開発している企業です。またSQLとPL/SQLコンサルタント会社でもあります。主にパフォーマンス最適化をしています。私はSQLトレーニングを実施し今年はSQLの本を書いています。」
InfoQ「HibernateやSpeedment、Apache Torqueなど他のJava ORMフレームワークとjOOQが異なる点は何ですか?」
Eder「個人的には実装の詳細に加えて互いの哲学やアプローチ、それぞれの実装の考えを比較することに強く興味があります。
RDBMSと連携するには主に5つのアプローチがあると思います。そのそれぞれで例としていくつかのプロダクトを列挙しますが、決して完全ではありません。
- Javaの外にSQLロジックを保持する
MyBatis、ベンダー特有のストアドプロシージャ、ビュー、jOOQストアドプロシージャ
- SQL文字列としてJavaにSQLロジックを組み込む
JDBC、jOOQプレーンSQL、Spring、JDBi、JPAネイティブクエリ
- SQL中心の内部ドメイン固有言語でJavaにSQLロジックを組み込む
jOOQ, Criteria API (JPQLのためのもの、SQLではない)
- "特有の"コレクションAPIとしてJavaにSQLロジックを組み込む
Speedment、JINQ、Slick (Scala)、LINQ (.NET)
- オブジェクトリレーショナルマッピングもしくはアクティブレコードを通じてJavaにSQLロジックを組み込む
JPAとその実装、HibernateやjOOQ UpdatableRecords、ActiveJDBCを含むこうしたアプローチはすべてそれぞれの長所と短所があります。jOOQは初めの3つのアプローチを重視します。なぜなら3つすべてがSQL中心であり、これはSQL言語がユーザがどのようにデータベースとやり取りしたいかにおける重要な部分であることを意味するからです。こうしたユーザにとって、"特有の"コレクションAPIやORMが押し付けてくる認知の不一致は高くつきます。彼らはただSQLを書きたいだけなのです。
jOOQの主な機能は流れるようなAPIがサポートしているコード生成です。これは高レベルのコンパイル時での型安全をSQL言語に過剰に妥協することなく開発者に提供します。この内部DSL技術についてブログに投稿しました。
https://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course
同時に、jOOQはまた開発者に次のことを推奨します。
- ビジネスロジックをビューやストアドプロシージャを通じてデータベースに押し込む。こうすると、jOOQをとても使いやすくなります。
- 最新の標準やベンダー特有のSQL機能を使う。分析やレポートをする時にとくに役立ちます。
- RDBMS中心の手法で考える。システムがありふれた単一クライアント、10テーブルのデータベース以上に成長した時にとてもよい作業の方法です。
もちろん、ここで興味深いことは、異なるアプローチが必ずしも互いに競合するものではないことを理解することです。多くのjOOQユーザは同一のアプリケーション内でHibernateも使います。たとえば次のようにです。
- jOOQは分析やETL、レポート、複雑な問い合わせに。
- Hibernateはトランザクションで多くのエンティティを更新するときの複雑なCRUDに。
最後に、実装としてjOOQはこうしたことをきちんと探している顧客にSQL言語の重要性を強調します。あえて言いますが、SQLがしばしば彼らが考えていたよりも多くの問いへのより良い回答であることを顧客が理解する助けとなります。」
InfoQ「jOOQを使っているパートナーと顧客について私たちに何を伝えたいですか?」
Eder「jOOQは彼らを広く優れた開発者にする手助けをします。説明させてください。
私は絶えず顧客のベースがどれほど異なっているのかを学ぶ策をめぐらせています。もともと私たちは私たちのように働き考える企業のためにjOOQを設計してきました。Data Geekeryを設立する前、巨大なスイス銀行のネットバンキングシステムのチームで働いていました。今日、私はまだ彼らをOracleのSQLパフォーマンス問題で手助けしています。当然、彼らはOracleでjOOQも使っています。
そのシステムはおよそ500のテーブルと、そのいくつかは10億行あり、何千のビューがあり、 何百のPL/SQLパッケージがあります。本当にたくさんのJavaコードもともにあります。多くのビジネスロジックは深くネストしたSQLビューとプロシージャに実装されています。もちろん、このシステムは他のたくさんの方法で構築できたでしょう。しかしSQL中心のこのシステムはOracleデータベースで本当によく動作するとてもエレガントな設計に至りました。
すべての企業が上記のような複雑なデータベースを持っているわけではありません。それにもかかわらず、これらの企業にとってjOOQを際立たせているものはjOOQがJava/SQL開発にもたらす単純さと楽しさです。はい、SQLは古い言語です。すべてのキーワードと興味深い構文にしばしば癖があると感じます。(最近これについてブログに投稿しました。 https://blog.jooq.org/2016/12/09/a-beginners-guide-to-the-true-order-of-sql-operations/)
しかし関係代数に着想を得た言語を使った宣言型プログラミングには卓越した美しさがあります。jOOQでSQL文をシンプルに直感的に書くことができるのは、本当に開発者を元気づけます。多くの顧客から私が聞いたもっともすばらしいことは、どれほどjOOQが彼らに好奇心とともにSQLの広大でわくわくする世界を見つける手助けとなったか、ということです。
言い換えると、私たちは単にすばらしい顧客に変化を促しているだけなのです。そしてそういった顧客はすべての業界にいます。」
InfoQ「近い将来jOOQに何がありますか?」
Eder「私たちはSQLに関連することすべてを愛しています。現在ビルトインのSQLパーサーで実験しています(バージョン3.9で追加しました)。ええ、jOOQは“単なる”SQL式のツリーモデルのライブラリです。SQL文をjOOQで構築するユーザは文字列を構築せず、式のツリーを構築します。それからこれがSQL文字列を生成します。どうして逆の方法をせず、SQL文字列をjOOQの式ツリーに解析しないのでしょうか?こうすることでユーザがSQL文字列(たとえばDB2)から他のSQL文字列(たとえばPostgreSQL)に変換できるようになります。レガシーなデータベースを移行するためのすごいツールです。そのままにしておくだけです!
jOOQにはすでにビルトインのSQL変換SPIがあります。これによって前述の式ツリーを他のものに変換できます。ここでありえるすばらしい機能はマルチテナンシーや行レベルセキュリティ、パフォーマンス最適化などのようなものです。これらの機能は高価な商用データベースならすぐに利用できますが、多くのオープンソースのものはそうではありません。私たちはもうフレームワークがあります。今後は、それをベースに機能を提供するでしょう。
SQL:2011標準のもっともよい機能の1つは一時クエリの書き込みができることです。あなたが保険企業にいて与えられたポリシーが変更されたと考えてみてください。典型的なSQLと違って、UPDATE文でレコードを実際に更新しません。異なった一時的妥当性を持つ、論理的に同じポリシーとして新しいレコードを作ります。SQL:2011は内部的に複数のUPDATE文やINSERT文に変換される、一時的なUPDATE文の透過的な書き込みを許します。一時的なDELETE文でも同様です。私たちはすべてのデータベースでこの機能をエミュレートすることを詳しく調べています。これには一時クエリをサポートしていないものも含みます(OracleやDB2以外のほとんどのDBです)。
さらに多くのものがあります。SQL言語は巨大なエコシステムですし、私たちはすべてのことをSQLとして受け入れます。なので、よりおもしろいjOOQのリリースを楽しみにしていてください!
情報
jOOQについてのより詳細な情報は次の記事にあります。
- jOOQはじめの一歩
- Josh LongによるSpringのTips: jOOQ動画
- jOOQでの動的SQLへの関数型プログラミングアプローチについてのjOOQのブログ投稿
- JDBCとjOOQでOracle 12cの暗黙カーソルをフェッチする方法についてのjOOQのブログ投稿
Rate this Article
- Editor Review
- Chief Editor Action