Liquibase、H2databaseでdropAll()できない
表題ままです。1週間悩んでました。
流れとして、
-
テストコード書きたい
-
DBにテストデータ入れたい
-
テストを独立させるため@Beforeでテーブル作成、@Afterで全て消したい
-
消えない(エラー終了)
最初はH2databaseとLiquibaseの相性とかいろいろ考えてました。
foreign key,view,tableを消す処理を自前で作ることも辞さない勢いでした。
が、落ち着いてログを見るとスキーマ名とテーブル名がダブルクオートで囲われている。
まさかと思ってソースを見ると、わざとそういった処理をしていました。
そのためそこだけオーバーライドしてよけたらうまくいっちゃった。
自己満足のためにgistで公開してみました。
Solve my way of exception on liquibase.dropAll(),using H2database(MODE=MYSQL)
Liquibase-3.1.1、 h2database-1.4で確認しています。
プロジェクトのソースに横槍を入れるなどおごがましいと考えているので、
絶対に他にやり方があると思います。
1週間の戦いに勝ったので、今日はマッカランで1杯やって寝ます。
DropwizardのテストからLiquibaseを知る
DropwizardのDAOテスト用DBをどうしようかと悩んでいたらこれを知りました。
最初はmockitoを使ってやりきろうと思ったけど、SQLのクエリも見たいのと
ログイン周りでSessionを使っているのでこれを選択。
DBをバージョン管理できるすごいやつ。
今回はMySQLの既存のスキーマをxmlにダンプして、h2 dabatase(in memory)に
再構築してテスト用DBを作ろうと頑張ってみました。
Dropwizardに食わせるDB設定は本番環境とテスト環境で設定ymlを分ければいいので楽です。
できたこと:
-
xmlのテンプレートを作っておく(Step 1参照)
Liquibase | Database Refactoring | Liquibase Quickstart<必要ないかもしれません
-
設定項目をliquibase.propertiesに記載
Liquibase使い方(基本)メモ - Qiita -
ダンプ
- java -jar [liquibase.jarのpath] --defaultsFile=[上記で作ったliquibase.properties] generateChangeLog
- liquibase.jarとDBドライバはDropwizardのプロジェクトで使用(依存)しているものにリンクを張るとバージョンで悩まない
- 上記だとログ作成時にymlパーサーが見つからないとINFOが出たが今回は無視
- クラスパスをきっちり指定している人は大丈夫だと思う
-
h2 databaseへの再構築(一部)、Dropwizardのテストでの使用
上記で作成したxmlをdropwizard-migrationで使用
Java - dropwizard-testingが便利でした - Qiita
できなかったこと:
目的は達成できたので満足です。
いずれバージョン管理にも手を出したいところ。
Dropwizardをデプロイ後、8時間後にDB接続エラー
デプロイしていよいよ起動、明くる日に様子を見るとページからログインできない。
ログインボタンを押してもレスポンスがない。
応答を見ると[500 Internal Server Error]。
バグ?ログを見てみると以下。
とか出ている。autoReconnect=trueにすると解決すると誘われている。
デフォルトでは最後の接続から8時間経つと切断されるらしい。
調べるとmysqlのpathの最後に?autoreconnect=trueで解決するとか。
しかし非推奨で、コネクションプーリングしなさいとのこと。
dropwizard特有のやり方とかあるんじゃないのとさらに調べる。
見つかる。例によって外人。
java - Broken Pipe exception in Dropwizard application - Stack Overflow
-
設定+αで解決した報告
- checkConnectionWhileIdle: true
- checkConnectionOnReturn: true
- checkConnectionOnBorrow: true
とソースのトランザクション境界で直ったらしい。(関係ない気がするけど)
自分のやつはユーザー認証と掲示板読み書き程度、それぞれでAbstractDAOの継承クラスによるアクセスと@UnitOfWorkをつけているのでいいはず。 -
コネクションプーリングしなさい
1の投稿のすぐ下にある。Manageを使おうとのこと。
ManagedPooledDataSource.javaとかいうド直球なソースが紹介されているけど、
これとdropwizard-hibernateを絡ませなきゃいけない。すぐには手が出せそうにないので後回し。
今回は1の方法で、最後の接続から8時間後に接続して解決したのでひとまず良しとします。
Dropwizardのassetsに/をmappingしたい
Dropwizardにおいて、静的なファイル(html, js, css…)はデフォルトでは
- http://{ドメイン}/assets/* → "src/main/resources/assets/*"
となっています。
ですが、トップページなどはURL直接指定でアクセスできると格好良かったりします。
先記のデフォルトは一応AssetBundleを使用することで変更できますが
ルートにはできない仕様らしいです。
Asset bundles not able to be served from root path. · Issue #661 · dropwizard/dropwizard · GitHub
Google先生に聞くと外人がたくさん困ってましたが、
ログを一生懸命漁っていると解決した声を見つけました。
上記リンクの下のほうにあり、まとめると
-
Application#initialize()において
bootstrap.addBundle(new AssetsBundle("/assets/", "/"));
-
Application#run()において
environment.jersey().setUrlPattern("/services/*");
1つめでやりたいことやって(従来はだめでしたが)、
2つめでjerseyのマッピングをしています(ここでは"/services/"以下)。
Dropwizardのjerseyはルートがデフォルトなので、
2つめがないと静的ファイルをjerseyで解決しようとして404になります。
( 2つ目の項目ですが、公式ドキュメントにあるように、
設定ファイルにapplicationContextPathを設定してもうまく動作しませんでした。)
日本語が少なくて大変…
DropwizardにおけるHibernateでのテーブル名定義箇所
今回一番引っかかったところ。
Dropwizardに組み込まれているHibernateのテンプレートクラスは、
- 設定ファイルに接続情報を記載
- Pojoの定義
- AbstractDAOの継承
- HQLを@NamedQueryで宣言、呼び出し
- サービス登録
だが、テーブル名の定義が@Tableと@NamedQuery内の2箇所であり、
どっちを使ってるのかいまいち。
そこで実験してみました。
というより今回引っかかったのでついでにいろいろ試しただけです。
大文字小文字の区別をこんな感じでしてみました。
Dropwizardのバージョンは0.7.0です。
No | SQLテーブル名 | POJOクラス名 | @Table | @NamedQuery | 結果 |
---|---|---|---|---|---|
1 | BBSDATA | BBSData | BBSData | BBSData | クエリ呼び出し時にNG MySQLSyntaxErrorException: Table 'Schema.BBSData' doesn't exist |
2 | BBSDATA | BBSData | BBSData | BBSDATA | Dropwizard起動時にNG QuerySyntaxException: BBSDATA is not mapped |
3 | BBSDATA | BBSData | BBSDATA | BBSData | OK |
4 | BBSDATA | BBSData | BBSDATA | BBSDATA | Dropwizard起動時にNG QuerySyntaxException: BBSDATA is not mapped |
5 | BBSDATA | BBSDATA | BBSData | BBSData | Dropwizard起動時にNG QuerySyntaxException: BBSData is not mapped |
6 | BBSDATA | BBSDATA | BBSData | BBSDATA | クエリ呼び出し時にNG MySQLSyntaxErrorException: Table 'Schema.BBSData' doesn't exist |
7 | BBSDATA | BBSDATA | BBSDATA | BBSData | Dropwizard起動時にNG QuerySyntaxException: BBSData is not mapped |
8 | BBSDATA | BBSDATA | BBSDATA | BBSDATA | OK |
意外だったのがPOJOのクラス名をみている?こと。
考察してみる。
- No1とNo3より、SQL問い合わせは@Tableを使用してるっぽい。
- No2、4、5、7より、"not mapped"と叱られているのは@NamedQuery。
- また、No2、4、5、7はPOJOクラス名≠@NamedQuery。
- 成功しているNo3、No8はPOJOクラス名=@NamedQuery。
これらより、
@NamedQueryに出てくるPOJOクラス名を@Tableで置換しているのか?
と推測。
Dropwizard勉強中のTips②
考えてみれば当たり前なんだけど、Dropwizardはjerseyを使ってるから
調べるときもjersey(JAX-RS)で検索したほうがかかりやすい、と。
ただ、今使ってるのDropwizardは0.7。
0.8がすでに存在し、jerseyのバージョンが上がって結構変わるらしい。
HK2とか言う記述をチラッと見たけど、
とりあえず0.7で一通り完成させてから対応させるつもり。