2015年8月29日土曜日

Maven pluginでプロジェクトのビルドアウトプットに依存する方法

Guide to Maven Classloadingによると、Maven pluginはPlugin classloaderでクラスがロードされます。
プラグインのdependenciesに設定されたライブラリはロードされるけど、プラグインが設定されたプロジェクトのビルドアウトプットやdependenciesに設定されたライブラリを見ることはできない。

どうしても、プラグインからプロジェクトのビルドアウトプットを参照できないとダメなときは、Mojoでカスタムクラスローダを使ってロードする必要がある。例えば、Mojoから使うライブラリがClassオブジェクトを要求する場合なんかは、自分でカスタムクラスローダ使って頑張る必要がある。

Stackoverflowいい解決案があるので、これを参考に対応するのがよい。→Maven plugin can't load class

自分は、最も+1された回答を参考にしてみました。
やった内容は、大きくしたの2点になります。

MavenProjectをMojoにインジェクトする

Mojoのフィールドで、MavenProjectを受け取ります。
    @Parameter(defaultValue = "${project}", required = true, readonly = true)
    private MavenProject project;

カスタムクラスローダを使ってクラスをロードする

MavenProjectのgetRuntimeClasspathElementsを使って、クラスパスに設定されているパスを取得して、カスタムクラスローダを作ります。
getRuntimeClasspathElementsが返す値は、MojoアノテーションのrequiresDependencyResolution属性に指定した値によって変わります。
属性を指定しない場合は、target/classesだけが取得されます。ResolutionScope.RUNTIMEを設定すると、dependenciesに設定したライブラリも取得されます。
    private URLClassLoader createClassLoader() {
        List runtimeClasspathElements;
        try {
            runtimeClasspathElements = project.getRuntimeClasspathElements();
        } catch (DependencyResolutionRequiredException e) {
            throw new RuntimeException(e);
        }

        final URL[] urls = runtimeClasspathElements.stream()
                .peek(s -> System.out.println("classpath:" + s))
                .map(s -> {
            try {
                return new File(s).toURI().toURL();
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }).toArray(URL[]::new);
        return new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
    }

[CSS3]attribute selector

attribute selectorは属性値を使って要素を選択できるセレクター。

使い方は、簡単で[]内にattribute selectorを定義する。
[attribute selector] {
}

/* attributeという属性を持つ要素を選択 */
[attribute] {
}

/*
class="hogs"を持つ要素を選択
class="hogs fuga"はマッチしないので選択されない
*/
[class="hogs"] {
}

/* class属性の値がhogeから始まる要素を選択 */
[class^="hoge"] {
}

/* class属性の値がfugaで終わる要素を選択 */
[class$="fuga"] {
}

/*
class属性の値の中で、スペースで区切られた値「hoge」がある要素を選択

class="hogs fuga"やclass="hoge"が選択される
*/
[class~="hoge"] {
}

2015年8月6日木曜日

PostgreSQLのpsqlでテーブル定義を確認する

psqlメタコマンドの\d テーブル名で確認することができる。

実行例

=> \d hoge
 テーブル "public.hoge"
  列  |   型   | 修飾語
------+--------+--------
 id   | bigint |
 name | text   |

2015年7月27日月曜日

eclipselinkでbatch insert

eclipselinkでは、jdbc.batch-writingjdbc.batch-writing.sizeの2つのプロパティを指定することでbatch insertが使用されます。

jdbc.batch-writingには、基本的にjdbcを指定すればよく、jdbc.batch-writing.sizeにはバッチサイズを指定する。

例えば、以下のように設定するとバッチサイズは100となります。

<properties>
  <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />

  <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>

  <property name="eclipselink.jdbc.batch-writing" value="JDBC" />
  <property name="eclipselink.jdbc.batch-writing.size" value="100" />
</properties>

結果を見ると、batch insertのほうが早くなっているのがわかります。

batch insertあり
---------- 1回目: 625ms ----------
---------- 2回目: 319ms ----------
---------- 3回目: 274ms ----------

batch insertなし
---------- 1回目: 1630ms ----------
---------- 2回目: 1342ms ----------
---------- 3回目: 1146ms ----------

2015年7月22日水曜日

hibernateでbatch-insert

hibernate.jdbc.batch_sizeに任意の数字を指定すると、その値が自動的にJDBCのバッチサイズになります。

例えば、以下の設定を行うとバッチサイズは100となります。

<properties>
  <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
  <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
  <property name="javax.persistence.jdbc.url" value="url"/>
  <property name="javax.persistence.jdbc.user" value="user"/>
  <property name="javax.persistence.jdbc.password" value="password"/>

  <property name="hibernate.jdbc.batch_size" value="100" />
</properties>

試しに以下のコードでbatch insertの効果があるのか確認してみます。
private static void insert(EntityManager em) {
        final EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        for (int i = 1; i <= 1000; i++) {
            final UserEntity entity = new UserEntity();
            entity.setName("name_" + i);
            em.persist(entity);
        }
        transaction.commit();
    }

結果をみると、batch insertの効果で5倍ぐらい早くなっているのがわかります。

batch insertあり
---------- 1回目: 766ms ----------
---------- 2回目: 390ms ----------
---------- 3回目: 317ms ----------
batch insertなし
---------- 1回目: 2369ms ----------
---------- 2回目: 2347ms ----------
---------- 3回目: 1589ms ----------

2015年7月19日日曜日

PostgreSQLのsleepファンクション

pg_sleepを使うことでデータベースサーバ側でsleep処理ができる。
pg_sleepの引数には、sleepしたい秒数を指定する。

-- 5秒sleep
select pg_sleep(5);
 pg_sleep
----------

(1 行)

時間: 5016.963 ms

-- 3秒sleep
select pg_sleep(3);

 pg_sleep
----------

(1 行)

時間: 3001.497 ms

2015年7月5日日曜日

IS DISTINCT FROM演算子

IS DISTINCT FROM(IS NOT DISTINCT FROM)演算子の使い方。PostgreSQLでは使うことができる。Oracleは12c時点では使うことができない。
この演算子を使うと、一方がnullの可能性がある場合の条件をcol1 = :col1 or col1 is nullのようにnullを考慮する必要がなくなる。

使い方

IS NOT DISTINCT FROMは、以下の条件と同じ動きとなる。
(expo IS NOT NULL
AND exp2 IS NOT NULL
AND exp1 = exp2)
OR (exp1 IS NULL AND exp2 IS NULL)

検索対象のデータ

データの内容(@は、nullを示しています)
select * from test;
 col
-----
   1
   2
   3
   @
(4 行)

IS NOT DISTINCT FROM

is not distinct from nullとするとnullのレコードのみ取得できる。
select * from test where col is not distinct from null;
 col
-----
   @

条件を指定すると、そのレコードのみ取得できる。
select * from test where col is not distinct from 3;
 col
-----
   3
(1 行)