id:torutk:20090622の続きで、GrailsからSQLite3データベースを使う方法の模索です。
GrailsはデータベースマッピングにHibernateを使っています。Hibernateは残念ながらSQLiteをサポートしていません。そこで、HibernateにSQLiteを扱わせるため、org.hibernate.dialect.Dialectクラスを派生したSQLiteDialectクラスを用意します。
次に、Grailsアプリケーション実行時にこのSQLiteDialectを読み込ませる設定を行います。
SQLiteDialect
誰か既に作成していないかと探してみると、2つほど見つかりました(以下URL)。
http://code.google.com/p/hibernate-sqlite/
http://github.com/gwenn/sqlite-dialect/blob/73d07f0990ecfd9b9a869066b8f7b3e023af39ff/org/hibernate/dialect/SQLiteDialect.java
ここでは前者のサイトからダウンロードし、dialect/SQLiteDialect.class 1つだけをJARファイル化します。
~$ jar cvf sqlitedialect.jar dialect ~$
このsqlitedialectと、id:torutk:20090611で記載のsqlitejdbcの2つのJARファイルを、Grailsのプロジェクトディレクトリのlib下にコピーします。
grails-app/conf/DataSource.groovy
次に、SQLiteを使うよう記述を変更します。
dataSource {
pooled = true
driverClassName = "org.sqlite.JDBC"
username = ""
password = ""
dialect = dialect.SQLiteDialect.class
}
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:sqlite::memory:"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:sqlite::memory:"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:sqlite:sqlite.db"
}
}
}
- dialectの記述では、.classを付けないものを見かけますが、.classを付けないと、CouldNotDetermineHibernateDialectException例外がスローされてしまいます。この例外は、HibernateDialectDetectionFactoryBean.javaでスローされるもので、に記述されています。そこから先は追えていません。
- (2009/12/2追記) grails-1.2.0-SNAPSHOTでは、dialectの記述に.classがあるとCouldNotDetermineHibernateDialectException例外が発生していました。試しに.classを削除すると起動しました。
- "jdbc:sqlite::memory:"は、SQLiteのインメモリデータベースを指定するものであり、再起動すると消えます。
実動(production)モードでは2回目に起動するとエラー
さて、一見調子がよさそうに見えたのですが、実動モードで起動、すなわちSQLiteのファイルデータベースを指定した場合、2回目の起動でSQLException例外がスローされます。
Caused by: java.sql.SQLException: not yet implemented
at org.sqlite.MetaData.getImportedKeys(MetaData.java:503)
at org.hibernate.tool.hbm2ddl.TableMetadata.initForeignKeys(TableMetadata.java:141)
at org.hibernate.tool.hbm2ddl.TableMetadata.<init>(TableMetadata.java:57)
at org.hibernate.tool.hbm2ddl.DatabaseMetadata.getTableMetadata(DatabaseMetadata.java:113)SQLiteJDBCのソースをダウンロードし、org.sqlite.MetaDataのgetImportedKeysメソッドを見ると、
public ResultSet getImportedKeys(String c, String s, String t) throws SQLException { throw new SQLException("not yet implemented"); }
となっており、確かに例外が発生します。しかし、これでは困るので、他にJDBCドライバがないかと探してみたところ、上述では試していないSQLiteDialectクラスのもう一つの作成者(gwenn氏)が、SQLiteJDBCを作成・公開していました。
http://github.com/gwenn/sqlitejdbc/tree
gwenn氏のSQLiteJDBCは、上記でエラーになったhttp://www.zentus.com/sqlitejdbc/のVer.054からフォークしたものとのことです。
gwenn版では、MetaData.getImportedKeysメソッドが実装されています。
public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { return getForeignKeys(null, table, false); }
そこで、gwenn氏のsqlitejdbcを使用することにします。
まず、上記URLをWebブラウザで開き、[download]ボタンをクリックします。ZIPかTARかを選択する画面が出てくるので、とりあえずZIPを選択して保存します。
次に、ダウンロードしたファイルを展開して、makeを実行し、生成されるjarファイルにネイティブライブラリを追加します。この手順は、Makefileの先頭のコメントに記述されてます。
~$ unzip gwenn-sqlitejdbc-XXXXX.zip
~$ cd gwenn-sqlitejdbc-XXXXX
gwenn-sqlitejdbc-XXXXX$ make
:
gwenn-sqlitejdbc-XXXXX$ cd build
build$ mv Default-i686/libsqlitejdbc.so linux-x86.lib
build$ jar uf sqlite-jdbc-v054-native.jar linux-x86.lib
build$ このSQLiteJDBCのJARをプロジェクトのlib下にあるものと置き換えで、再度実動モードで実行したら、例外はスローされることなく起動しました。