LoginSignup
35
34

More than 5 years have passed since last update.

iciqlで実現するSQL DSLとJDBCリファクタリング

Last updated at Posted at 2015-02-01

iciqlとは?

 
 iciqlはJavaのO/R Mappingで,特徴は軽量なSQL DSL(domain-specific language: ドメイン固有言語)です。とても可読性が高い文法が魅力的なので,紹介します。
 
 

iciql SQL DSLの例

 iciql SQL DSLの例を見てみましょう。

IcliqlSampleMain.java
Senryu t = new Senryu();
List<Senryu> dbData =
        db
                .from(t)
                .where(t.category).oneOf("09", "15")
                .and(t.sql).like("%SELECT%")
                .and(t.count).lessThan(1)
                .orderByDesc(t.updatedate)
                .orderBy(t.idSenryu)
                .select();

 
 次のSQLが発行されます。

IcliqlSampleMain.sql
SELECT *
FROM   senryu
WHERE  category IN( '09', '15' )
   AND sql LIKE '%SELECT%'
   AND count < 1
ORDER  BY updatedate DESC,
          id_senryu 

 
 

Fluent Interface

 iciqlの文法が懐かしい開発者も多いと思います。これは,2005年にEric EvansとMartin Fowlerが提唱した「流れるようなインタフェース」(fluent interface)が源流で,2007年にSeasarのS2JDBに採用されたり,Ruby on RailsのActive Record,最近ではScalaのSlickなど,Web開発者には馴染みがある文法のためです。
 
 

SQL DSLのメリット

 SQL DSLのメリットは,タイプセーフ(type-safe)の一言に尽きます。
 
 テーブルが変更された場合に,JavaとSQLとの境界が文字列のORMだと,実行時エラーまで気づかないことがあります。SQL DSLでタイプセーフに記述すると,コンパイルエラーで気づくことができます。

 
 

iciqlのメリット 

 iciqlのメリットは,jarファイルひとつで動作することです。

  1. jarファイルひとつで軽量動作(依存なし)
  2. 設定ファイル不要
  3. OSS(活発ではない)
  4. タイプセーフ&流れるようなインタフェース
  5. DBからモデルを生成するツールもある(公式ページの解説は古い)  

 流れるようなインタフェースでタイプセーフのJava ORMは,S2JDBCだとSeasar依存,jOOQは有料など,それぞれ偏りがあります。iciqlはバランスが良いです。
 
 

SQL DSL x Java 8 ラムダ式

 テーブルモデルのSQL DSLとラムダ式を組み合わせは,コードの相性が良く,可読性が向上します。

 Java JDBC SQL周りのリファクタリングに興味を持たれた方は,GitHubに掲載したiciql x Java 8 ラムダ式のソースコードも是非ご参照ください。

IcliqlSampleMain.java
public static void main(String[] args) {

    Db db = null;

    try {
        /*==================================================
         * Instantiating a Db
         *==================================================*/
        String url = "jdbc:postgresql://localhost:5432/sqlsenryu";
        String user = "sqlsenryu";
        String password = "sqlsenryu";
        db = Db.open(url, user, password);

        /*==================================================
         * SQL DSL > Select Statements
         *==================================================*/
        Senryu t = new Senryu();
        List<Senryu> dbData =
                db
                        .from(t)
                        .where(t.category)
                        .oneOf(
                                CommonConst.Category.SQLite,
                                CommonConst.Category.PostgreSQL)
                        .and(t.sql).like("%SELECT%")
                        .and(t.count).lessThan(1)
                        .orderByDesc(t.updatedate)
                        .orderBy(t.idSenryu)
                        .select();

        /*==================================================
         * Lambda Expression
         *==================================================*/
        dbData
                .stream()
                .filter(
                        x -> x.category
                                .equals(CommonConst.Category.PostgreSQL))
                .forEach(y -> {
                    print(y);
                    update(y);
                });

        dbData
                .stream()
                .filter(x -> x.category.equals(CommonConst.Category.SQLite))
                .forEach(y -> {
                    print(y);
                });

        /*==================================================
         * SQL DSL > Update Statements
         *==================================================*/
        db.updateAll(dbData);

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (db != null) db.close();
    }
}

private static void update(Senryu senryu) {
    senryu.updatedate = new Timestamp(System.currentTimeMillis());
    senryu.count++;
}

private static void print(Senryu senryu) {
    System.out.println(senryu.toString());
}

参考資料

付録

  • iciqlの開発者は,ひとつのwarファイルデプロイでGitサーバを手軽に構築できる"gitblit"を開発したJames Moger氏です。2011年に公開され,最新リリースは2014-11-10のVer.1.5.0です。  
  • iciqlの読みは「イシキュエル」説。 イシキュエル -> シークェル -> SQLを有力視しています。  
  • iciqlのテーブルモデルはアノテーションを使用してテーブルとカラムの属性を定義します。設定ファイルレスが良いです。
Senryu.java
@IQTable(
        create = false,
        name = "senryu",
        memoryTable = false,
        annotationsOnly = true,
        inheritColumns = false)
public class Senryu {

    @IQColumn(
            primaryKey = true,
            name = "id_senryu",
            trim = false,
            scale = 0,
            length = 0,
            nullable = false,
            defaultValue = "",
            autoIncrement = false)
    public long idSenryu;

    @IQColumn(
            primaryKey = false,
            name = "category",
            trim = false,
            scale = 0,
            length = 2,
            nullable = false,
            defaultValue = "",
            autoIncrement = false)
    public String category;

    public String toString() {
        return String.format(
                "%d %s %s",
                idSenryu,
                category);
    }
}

 ‡SQL DSL以前の世界は・・・

PreparedStatementSampleMain.java
StringBuffer  sql = new StringBuffer();
sql.append("SELECT * ");
sql.append("FROM   senryu ");
sql.append("WHERE  category IN( ?, ? ) ");
sql.append("   AND sql LIKE ? ");
sql.append("   AND count < ? ");
sql.append("ORDER  BY updatedate DESC, ");
sql.append("          id_senryu");

PreparedStatement pstmt = conn.prepareStatement(sql);

pstmt.setString(1, "09");
pstmt.setString(2, "15");
pstmt.setString(3, "%SELECT%");
pstmt.setInt(4, 1);
35
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
34