どうしてこの記事を書くことになったのか:
知恵袋みたいなアプリケーションに投稿されたデータを、チャットボット(もちろんIBM Cloud上の)から検索かけられたら強そう! 将来的に自然言語解析もできそう! と思ったので一時のテンションで始めたらエラーだらけだった。
前提
・IBM Cloudにアカウントがある
・Db2のリソースが作成済み(ライトアカウント)
わかるところから
DB2 via JDBC on Spring - IBM Developer
とりあえず検索して出てきた上記のページを参考に、application.propertiesを書く。
(IBM Cloud>リソース・リスト>作成したDb2>サービス資格情報 からURLなどの情報が取得できる)
spring.datasource.url=jdbc:db2://**************:50000/BLUDB
spring.datasource.username=********
spring.datasource.password=********
エラー1個目
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under '' to com.zaxxer.hikari.HikariDataSource:
Property: driverclassname
Value: com.ibm.db2.jcc.DB2Driver
Origin: "driverClassName" from property source "source"
Reason: Failed to load driver class com.ibm.db2.jcc.DB2Driver in either of HikariConfig class loader or Thread context classloader
Action:
Update your application's configuration
Stack Overflowのこの質問を参考にしてbuild.gradle
を編集した。
対処
dependencies {
runtime('com.ibm.db2:jcc:11.5.0.0')
}
エラー2個目
2020-00-00 15:21:58.916 ERROR 5080 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=END-OF-STATEMENT;select 1;<table_expr>, DRIVER=4.26.14
上記は起動時に発生するエラー。内容的にはSQLのシンタックスエラーだが、起動時にSQLを使った覚えがなく、ずっとimport.sql
が悪いのか?起動時にテーブルを生成する設定が悪いのか?などと考えていた。
しかし結局、ここで作動していたのは接続テスト用に(おそらくデフォルトで)設定されていたSQLだった……。
いろいろ調べていくうちに気づいたが、エラー文にあったSELECT 1
で検索を書けていたらもっと早く気づけたかもしれない。
spring.datasource.hikari.connection-test-query = SELECT 1
このSQL文がおかしいということで、Db2向けの適当なテスト用SQLがあるんじゃないか?と調べてみたけどヒットせず。
ならこのオプション外せばいいじゃんと思ったが、HikariCPでは代わりにConnection.isValid()
を実行するようになり、結局エラーが出た。
なら存在する任意のテーブルに対して何か操作すればいいんじゃないということで、適当にtestテーブルにカラムを一つ作成した。
対処
spring.datasource.hikari.connection-test-query = SELECT col1 from test
さらに数か所修正
-
spring.jpa.database-platform
をorg.hibernate.dialect.h2Dialect
からorg.hibernate.dialect.DB2Dialect
にしたり…(最初H2で作っていたので) - Javaのソースコード中のSQL文からセミコロンを外したり…(おそらく上記との兼ね合い)
- タイムアウトの時間を長くしたり…(ライトプランのせいか頻繁にタイムアウトする)
- pom.xmlを書き換えたり…(下記)
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<version>11.5.0.0</version>
</dependency>
アクセスできた!
本当にこれでいいのか? という疑問はありつつも一応アクセスできたのでOKとする。
すごい…ちゃんとブラウザ上にデータが表示されている…。
と思ったのもつかの間、
エラー3個目
2020-00-00 01:22:57.438 WARN 26912 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : [jcc][t4][10217][10310][4.26.14] 接続の確立後は、接続の読み取り専用モードを実行できません。
読み取り専用の接続を実行するには、読み取り専用データ・ソースまたは接続プロパティーを設定してください。 ERRORCODE=4474, SQLSTATE=01000
DriverManager.getConnection()
でアクセスしている分には出ないので、どうもJPARepositoryを介してアクセスしようとするとこのエラーになるらしい。
(混在しているのは自分で書いたコードと人の書いたコードが混ざっているせい……)
JPARepositoryを使わなければひとまず解決しそうだけど、普通に設定変えて使えるような気もする。
第二弾記事に期待。
まとめ
-
application.properties
かbuild.gradle
あたりが怪しい。 - エラー文をちゃんと読む
余談
Db2のダッシュボードにアクセスしようとすると延々とエラーを吐き続けるという不具合に当たったが、ダッシュボードのアドレスが分かれば、そちらにアクセスして、DBの認証で使っているusernameとpasswordを入力してアクセスすることができる。
リダイレクトするときに、IBMCloudのログイン情報からダッシュボードへの認証がうまくできなかったみたい。