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下にあるものと置き換えで、再度実動モードで実行したら、例外はスローされることなく起動しました。