memorandum

Webアプリ開発などを中心としたITに関するメモのブログです。

Spring Data JPAで複数テーブルを結合した結果を返すクエリを作る

2016/12/31
2021/02/25

少し前に検証したものだが、改めて整理。

テーブルAとテーブルBを結合した結果を取得したい場合に、普通にSpring DataのRepositoryを作って@Query のメソッドを定義してもうまくいかない。
例えば以下のようなクエリは表現できない。

select a.id, b.id, b.name from a join b on b.id = a.b_id;

これを何とかRepositoryで表現するための方法について。

続きを読む...

ElasticsearchのBouncing Results問題

2016/12/31
2021/02/25

Boucing Resultsという問題がある。検索結果に重複・欠落が起きる問題。

ソートのキーに使われる項目の値が同じdocumentがあると、検索結果の順序が一定にならない可能性がある。
Elasticsearchのクエリでページネーションを行う場合、各ページへのリクエストは独立しているので、それぞれのアクセスで別のシャードにアクセスする可能性がある。

  • 対象のElasticsearchクラスタがレプリカを持っている
  • ソート対象項目の値が同一の複数documentがページを跨っている
  • それらのページへのリクエストが別のシャードに割り当てられる
  • それぞれのシャードが対象のdocumentを返す順番が異なる

といった条件が揃うと、1ページ目で返された検索結果が次のページでも返ってくる、という事象が起きる。

これは、Elasticsearch: The Definitive Guide でも説明されている Bouncing Results という問題とのこと。

この問題と思われる事象に遭遇したため、事象の再現と対策の検証を行なった。

続きを読む...

Thymeleafの部品化

2016/12/31
2021/02/25

th:fragment によって部品を作るのは比較的簡単にできるが、類似の部品が出てきた時に、その中の一部を変更したい場合にどうするか?

例えば以下のようなイメージ。
barタグとbazタグだけが差分であり、その他は同じ構成になっている。

<foo id="foo1">
  <div></div>
  <bar></bar>
</foo>

<foo id="foo2">
  <div></div>
  <baz></baz>
</foo>

それぞれのfooタグを部品として定義するのも良いが、それでは重複コードが多すぎる。

続きを読む...

Gradleプラグインのup-to-dateを確認するテスト

2016/12/31
2021/02/25

GradleプラグインのTaskにInputとOutputを設定して、いずれかが変化した時にだけタスクが再実行されるようにしたいとき。
実装は簡単でも、テストはどうするか。
up-to-dateがきちんと判定できないと、変更が入った時に処理が実行されないなど致命的な不具合になる。
※Gradleのバージョンが古い(2.x)ので、最新では少し話が違うかもしれない。

続きを読む...

Spockで複数ステップのテストを書く

2016/12/31
2021/02/25

Spockでテストを書くとき、setup:, when:, then: という流れで書けば良いが複数の処理を実行し、最後の結果だけでなく途中の経過も含めてassertする場合にどうすればいいか。

単純に when:then: を繰り返して書けばいい。
and: などが一見それっぽいもののようにも思えてしまうが、and: はこの用途ではないので注意。

def ...() {
    setup:
    // 初期設定

    when:
    // 最初の処理

    then:
    // 最初の処理の結果をassert

    when:
    // 2つ目の処理

    then:
    // 2つ目の処理の結果をassert
}

続きを読む...

Springでauto_incrementなカラムに対して0を指定する

2016/10/30
2021/02/25

ユニーク制約の一部にNullableなカラムを含めたいが、それではユニークにならないので回避したい。

(a, b, c) という複数カラムのユニーク制約を定義したい場合に、この中にNULLを許可するカラムがありNULLが入ってきてしまうと、MySQLなどではユニーク性が担保されない。

これを回避するために NULL の代わりに 0 を使ってみたら良さそうだが、Springではどうやればいいのか?

続きを読む...

SpringのAOPでSQLエラーをハンドリングする

Spring BootでJDBCを使っていてSQLExceptionが発生した場合に、HibernateのSqlExceptionHelperが以下のようにERRORログを出力してしまう。

2016-10-30 13:56:45.772  WARN 40153 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 23502, SQLState: 23502
2016-10-30 13:56:45.772 ERROR 40153 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper   : 列 "TEAM_ID" にはnull値が許されていません
NULL not allowed for column "TEAM_ID"; SQL statement:
insert into tag (id, created_at, updated_at, account_id, name, team_id) values (null, ?, ?, ?, ?, ?) [23502-190]

未知の例外に対してはこの挙動でも問題ないように思うが、例えばデッドロックが発生した時にはリトライしたいとか、自分でハンドリングしたいケースがあった場合には、本当に問題といえる状態だと判断ができるレイヤでERRORログを出力するように制御したい。

…ということで、このログ出力を回避して自分でハンドリングする方法について。

続きを読む...

Spring Security 4.0ではHeaderWriterを使って静的リソースのキャッシュヘッダを適切につける

2016/10/30
2021/02/25

以前のエントリ
Spring BootでJavaScript/CSSライブラリにフィンガープリントをつける
Spring BootでJavaScript/CSSライブラリにフィンガープリントをつける (2)
の方法だけだと、フィンガープリントを付けることはできてもSpring Securityによりキャッシュ無効化のヘッダが付いてしまうためキャッシュされない。
そこで静的リソースについてはキャッシュヘッダを無効化してみて、一見 Cache-Control: no-cache のようなヘッダはなくなったかのように見えたが、Font Awesomeのアイコンがどうもちらつくな…と思って調べた。

すると、静的リソースについては全体的にキャッシュ系のヘッダを無効化していたものの、Expiresヘッダだけはついてしまっていた。
※Spring Boot 1.3.2 (Spring Security 4.0.3) を使用。

続きを読む...

© 2010 ksoichiro