谷本 心 in せろ部屋 このページをアンテナに追加 RSSフィード

2015-05-06

[][]Bootiful SQL Templateという名前にしてMavenリポジトリで公開しました。

年末に作ったSqlTemplateですが、自分の仕事でも使いたいっていうか使ってるので、

ソースコードを多重管理しなくて済むよう、Mavenリポジトリで公開することにしました。


こんな指定で使えます。

    <dependencies>
        <dependency>
            <groupId>ninja.cero.bootiful-sqltemplate</groupId>
            <artifactId>bootiful-sqltemplate-core</artifactId>
            <version>1.0.1</version>
        </dependency>
        ...
    </dependencies>

ドメイン名は、ninja.cero-tにしようかと思ったんですが、

ハイフンとかアンダースコアとかをURLに入れるな勢が多いので、

ninja.ceroっていうちょっと語呂のよくないドメイン名になっています。


そんな話はどうでも良くて。


ドキュメントはこれから書いていきますが、

今すぐ試してくれるという方は、テストを見てもらうのが良いと思います。

https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/


Spring Bootでの利用を前提としているので、まずはBean定義をします。

https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/java/ninja/cero/sqltemplate/test/TestConfig.java

@SpringBootApplication
public class TestConfig {
    @Bean
    SqlTemplate sqlTemplate(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
        return new SqlTemplate(jdbcTemplate, namedParameterJdbcTemplate);
    }
}

Spring BootじゃないSpringでも使えると思いますが、まったく試したことがありません。


呼び出し部分は、こんな感じ。

https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/java/ninja/cero/sqltemplate/core/SqlTemplateTest.java

    @Test
    public void testForList_MapArg() {
        Map<String, Object> param = new HashMap<>();
        param.put("deptno", 30);
        param.put("job", "SALESMAN");

        List<Emp> result = template.forList("sql/selectByParam.sql", Emp.class, param);
        // 略
    }

    @Test
    public void testForList_MultiArg() {
        List<Emp> result = template.forList("sql/selectByArgs.sql", Emp.class, 30, "SALESMAN");
        // 略
    }

複数オブジェクトを返すforListと、単一オブジェクトを返すforObjectメソッドがあり、

パラメータに使える引数は「Map」「ValueObject」「可変長引数」の3種類です。


肝心のSQLテンプレートですが、バインド変数には :name か ? の好みのほうを使えます。

https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/resources/sql/selectByParam.sql

SELECT
        *
    FROM
        emp
    WHERE
        deptno = :deptno
        AND job = :job
    ORDER BY
        empno

:name 形式のパラメータを使う場合、引数は「Map」か「ValueObject」になります。


https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/resources/sql/selectByArgs.sql

SELECT
        *
    FROM
        emp
    WHERE
        deptno = ?
        AND job = ?
    ORDER BY
        empno

? をパラメータとして使う場合、引数は「可変長引数」になります。直感通りだと思います。


また、SQLファイルを事前処理するためのテンプレートエンジンとして

FreeMarkerを組み合わせて使うこともできます。

https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/java/ninja/cero/sqltemplate/core/FreeMarkerTest.java

@SpringBootApplication
public class FreeMarkerConfig {
    @Bean
    SqlTemplate sqlTemplate(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
        return new SqlTemplate(jdbcTemplate, namedParameterJdbcTemplate, new FreeMarker());
    }
}

FreeMarkerを使ったテンプレートは、こんな書き方になります。

https://github.com/cero-t/sqltemplate/blob/master/sqltemplate-core/src/test/resources/ftl/selectByArgs.sql

SELECT
        *
    FROM
        emp
    WHERE
        1 = 1
<#if job??>
        AND job = :job
</#if>
<#if mgr??>
        AND mgr = :mgr
</#if>
<#if deptno??>
        AND deptno = :deptno
</#if>

FreeMarkerが先に事前処理をしてから、SQLテンプレートが解釈される形になります。


実装としては、ただのJdbcTemplateとNamedParameterJdbcTemplateのラッパーなので

たいした事はやっていません。

ただ、こんなシンプルなSQLテンプレートエンジンが欲しかったので、ひとまず形にしました。


SQLガ、イチバンヤー!

2014-12-15

[][]SqlTemplateっていうJdbcTemplateのラッパーを作ってみました。

SQLが書きたいんや!」という想いのもと、

Spring Bootと組み合わせて簡単に使える、

JdbcTemplateのラッパーライブラリを勢いで作ってみました。


GitHubに置いています。

https://github.com/cero-t/sqltemplate


JdbcTemplate / NamedParameterJdbcTemplateをベースにして、

 1. SQLファイルが使えること

 2. Date and Time APIに対応すること

 3. publicフィールドに対応すること

 4. APIが今風であること

の4つを目的にして作りました。


それならMirageでいいんじゃね? という想いは消えませんが、

Spring標準機能のみを使うことによる、政治的な使いやすさを取りました。


作りましたって言っても、ただのラッパーですので

ソースコードはすっごく小さくて、空行とコメントを入れても600行ぐらいしかありません。

ジェバンニでなくとも一晩でやってくれるぐらいのサイズです。


利用イメージ

exampleのプロジェクトも作っておきました。

https://github.com/cero-t/sqltemplate/tree/master/sqltemplate-example


使う側のソースコードは、こんな感じになります。

@Component
public class SampleProcess {
    @Autowired
    SqlTemplate query;

    public void process() {
        List<Emp> emps = query.forList("sql/selectAll.sql", Emp.class);
        emps.forEach(e -> System.out.println(e.ename));

        Emp emp = query.forObject("sql/selectByEmpno.sql", Emp.class, 7839);
        System.out.println(emp.ename);

        Map<String, Object> condition = new HashMap<>();
        condition.put("deptno", 30);
        condition.put("job", "SALESMAN");
        emps = query.forList("sql/selectByCondition.sql", Emp.class, condition);
        emps.forEach(e -> System.out.println(e.ename));
    }
}

forObjectで1件検索、forListで複数件検索。

第一引数SQLファイル名で、第二引数戻り値の型、

第三引数以降がSQLにバインドするパラメータです。


ちなみにIntelliJを使っていると、ファイル名にカーソルをあわせて

Ctrl (Command) + クリックでSQLファイルを開けるのが嬉しいですね。


SQLファイルは、こんな感じになります。

select
    *
from
    emp
inner join dept
    on emp.deptno = dept.deptno
where
    dept.deptno = :deptno
    and emp.job = :job

第三引数に指定したMapやEntityの値を、SQLパラメータとしてバインドします。

内部的にはNamedParameterJdbcTemplateに処理を委譲しているだけです。


名前を指定せずに ? を使うこともできます。

select
    *
from
    emp
where
    empno = ?

第三引数以降に指定した任意の数の基本型(String、Date、Number)をバインドします。

こちらは内部的にJdbcTemplateに委譲しているだけです。


使い方

使うための設定は一つだけ。

@Configurationアノテーションをつけたクラスに

SqlTemplateを返すメソッドを作り、@Beanアノテーションをつけます。

@Bean
SqlTemplate sqlTemplate(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
    return new SqlTemplate(jdbcTemplate, namedParameterJdbcTemplate);
}

この初期化の仕方は @ がpullリクエストで教えてくれました。

ありがとう!


ちなみにSqlTemplateのコンストラクタの第三引数には、

SQLファイルを読み込む際のテンプレートエンジンを指定することができます。

たとえばここで2-way SQLパーサーを指定すれば、

2-way SQLにも対応できるというスンポーです。


現時点でもFreeMarkerを使うことができるようにしているんですが、

一度も動作確認してないので、動くかどうか分かりません。てへぺろ


いまあるAPI一覧

用意したメソッドの一覧は、以下になります。

<T> T forObject(String fileName, Class<T> clazz, Object... args)
<T> T forObject(String fileName, Class<T> clazz, Map<String, Object> params)
<T> T forObject(String fileName, Class<T> clazz, Object entity)

<T> List<T> forList(String fileName, Class<T> clazz, Object... args)
<T> List<T> forList(String fileName, Class<T> clazz, Map<String, Object> params)
<T> List<T> forList(String fileName, Class<T> clazz, Object entity)

int update(String fileName, Map<String, Object> params)
int update(String fileName, Object entity)
int update(String fileName, Object... args)

戻り値をMapにする「forMap」とか

案件では欠かせない「batchUpdate」は、まだ作っていません。

委譲するだけなので、作っちゃえばいいんですけどね。


制限事項的なやつ

とりあえずコンセプト実証した程度なので、色々できません。

 1. 上に書いた通り、forMapとbatchUpdateがありません。

 2. JSR-310を使っているので、Java8でしか動きません。

 3. publicフィールドのないgetter/setterベースのJavaBeansは使えません。

 4. パッケージ名が変です。

 5. mvnリポジトリに置いてないです。

 6. README.mdちゃんと書け。


ひとまずは「こんなコンセプトでサクッとできたよ! 」っていう位置づけです。

自由に参考にしてください!

2014-12-14

[][]MyBatisをやめて、JdbcTemplateを使うわ。

以前のエントリーで、DBアクセスにはMyBatisを選んだと書きました。

http://d.hatena.ne.jp/cero-t/20141212/1418339302


そしたら渋谷JavaのLTで @ さんに拾ってもらっちゃいました。

http://www.slideshare.net/yukung/j-ooq-shibuyajava9


そんなこともあってMyBatisイチオシなエンジニアに思われたかも知れませんが、

ごめんなさい、

あの記事はあくまでも伏線で、僕、もうMyBatis使ってないんです!


MyBatisを使って半月ぐらいして、

どうにも我慢できなくないことが出てきました。


1. Spring Bootとの連携がイマイチ

Spring BootでMyBatisを使おうとすると、

前回のエントリーで書いた通り、ちょっと設定ファイルが必要になったり、

その設定ファイルの読み込みに失敗して、謎の無限ループが起きることがあるなど、

やや不可解なことがあります。


設定ファイルの問題というなら、設定ファイルを使わず、

ソースコードだけで設定できれば良いのですが、その方法も、結局よく分かりませんでした。


まぁMyBatisAutoConfigurationとかができてからが本番というか、

ないなら自分で作るゾ、ぐらいの勢いで挑む必要があるように思いました。


2. XMLSQLを書くと、インデントががが。

じゃぁMyBatisAutoConfigurationを作れば良いわけですが、

そういう気になれなかったのは、やっぱり、

XMLファイルにSQLを書くのが嫌だったから、でした。


だって、標準的なフォーマッタでフォーマットした瞬間、

インデントが全部消えるじゃないですか。


自動フォーマットをこよなく愛する僕としては、

フォーマットする手段がないというのは、いただけませんでした。


3. そこでJdbcTemplateですよ

じゃぁ何を使ってるのか?

で、結局、Springに標準でついているJdbcTemplateを使っています。


無設定で使えて、値のバインドは適切にできて、

NamedParameterJdbcTemplateならSQL変数が使えて、

Entityにはアノテーションとか付けなくて良くて、

余計な機能はなくて、シンプルに使える感じでした。


ただ、もちろん、JdbcTemplateも欠点だらけです。

 ・publicフィールドに対応していない

 ・Java8のLocalDateなど、Date and Time API (JSR-310) に対応していない

 ・RowMapperを求めるAPIになっているなど、APIに古くさいものが混ざっている

 ・そもそも、SQLファイルを読み込む機能なんてない!


なので、これらを補うような

独自ラッパーでラッピングして使うことにしました。


詳しい紹介はまた改めて書くとして、モノはここに置いています。

https://github.com/cero-t/sqltemplate


独自ライブラリではなく、Spring標準のJdbcTemplateを

ちょっとだけラッピングして使っているだけなので、

政治的な意味で使いやすいかな、と思っています。