jOOQ (http://www.jooq.org/) についてのメモ。 jOOQは、type safeかつdatabase orientedなクエリビルダーである。 database orientedなので、「アプリケーションからDBのことなんて全然意識したくないねん」的な思想に基いて作られた類のプロダクトとは異なり、思い通りのSQLを生成できるようになっている。
以下gradle前提で。version等はよしなに。
gradle
dependenciesはこんな感じ
compile 'org.jooq:jooq:3.7.1' compile 'org.jooq:jooq-meta:3.7.1'
テーブル等に相当するクラスをgradle taskから生成するためにbuildscriptのdependenciesにも以下をかいておく
classpath 'org.jooq:jooq-codegen:3.7.1'
んで、以下のようなコードをbuild.gradleに書く。MySQL前提です。細かい部分は自分の環境に合わせてよしなに。
def genXml = { db, writer -> new groovy.xml.MarkupBuilder(writer).configuration('xmlns': 'http://www.jooq.org/xsd/jooq-codegen-3.6.0.xsd') { jdbc() { driver("com.mysql.jdbc.Driver") url("jdbc:mysql://localhost:3306/") user("root") password("") } generator() { database() { inputSchema(db) } generate() { } target() { packageName("com.foo.bar.jooq." + db) directory("src/main/java") } } } } def generateJooqSources = { db -> def writer = new StringWriter() def xml = genXml(db, writer) org.jooq.util.GenerationTool.generate( javax.xml.bind.JAXB.unmarshal(new StringReader(writer.toString()), org.jooq.util.jaxb.Configuration.class) ) }
で、以下のようにデータベース毎にtaskを定義する、と。
task("jooq-generate-example") << { generateJooqSources(name) }
若干DRYではないがここでは気にしない。
初期化
単にクエリを発行するだけなら、ConnectionやDataSourceからDSLContextクラスのオブジェクトを作ればよい。
DSLContext ctx = DSL.using(dataSource, SQLDialect.MYSQL);
クエリの書き方
SQLでやりたいことは大体出来る。たまにめんどくさい書き方をする必要があるが...
以下、userというtableからコード生成して、適宜static importしている前提。
単品SELECT
UserRecord record = ctx.selectFrom(USER)
.where(USER.ID.equal(userId)
.fetchOneInto(UserRecord.class);
カラムを指定して単品SELECT
返り値を制御する関係で、結果として二回カラム名を指定する必要がある
String name = ctx.select(USER.NAME) .from(USER) .where(USER.ID.equal(userId) .fetchOne(USER.NAME);
複数SELECT
List<UserRecord> userRecords = ctx.selectFrom(USER)
.where(USER.NAME.equal(name)
.fetchInto(UserRecord.class);
特定のカラムの値をkeyにしたMapを取得
PerlのDBIでいうところのselectrow_hashref的なことも出来る。1対1のマップ。
Map<Integer, UserRecord> userRecords = ctx.selectFrom(USER)
.where(USER.NAME.equal(name)
.fetchMap(USER.ID, UserRecord.class);
特定のカラムの値をkey、keyの値でグルーピングされたレコードのListをvalueにしたMapを取得
PerlのDBIでいうところの…なんだっけ。あったっけか。1対nのマップ。
Map<Integer, List<UserRecord>> userRecords = ctx.selectFrom(USER)
.where(USER.ID.in(userIds))
.fetchGroups(USER.STATUS, UserRecord.class);
INSERT
ctx.insertInto(USER, USER.NAME, USER.STATUS)
.values(name, 0)
.execute();
batch INSERT
List<UserRecord> userRecords = new ArrayList<UserRecord>(); ... ctx.batchInsert(userRecords) .execute();
UPDATE
ctx.update(USER) .set(USER.NAME, name) .where(USER.ID.equal(userId)) .execute();
DELETE
ctx.deleteFrom(USER) .where(USER.ID.equal(userId)) .execute();
トランザクション
ctx.transaction(new TransactionalRunnable() { @Override public void run(Configuration configuration) throws Exception { // ここの中 } })
where条件の動的な組み立て
SelectQuery<UserRecord> query = ctx.selectFrom(USER).getQuery(); for (User u : users) { Condition condition = USER.NAME.equal(userName).and(USER.STATUS.equal(1)); query.addConditions(Operator.OR, condition); } List<UserRecord> userRecords = query.fetchInto(UserRecord.class);
DAO
使ったことはないが生成できるらしい
http://www.jooq.org/doc/2.6/manual/sql-execution/daos/
で、実際どうなん?
たまにかゆい所もあるけど、一通りのことは出来てまあまあ使いやすいです。
ドキュメントが結構充実しているのと、開発者がstackoverflowでこまめにレス付けてる所を見ると、気合の入っていることが分かります。
- 作者: ジョージリース,George Reese,石井史子,福龍興業
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2001/09
- メディア: 単行本
- クリック: 7回
- この商品を含むブログ (3件) を見る