ちょっとした理由でsqliteについて調べていました。そこで、sqliteでデータベースを指定するDSN(ドキュメント上はfilename)はファイル名や":memory:"だけでなくいろんな設定ができるようだったので、メモします。
sqlite3のDSN(filename)はURIにできる
sqliteの"filename"は、典型的にはファイル名を指定することが多いかと思います。たとえばhoge.db
にデータベースを保存している場合は、単純にこのファイルへのパスを渡すわけですね。
sqlite3_open("hoge.db", &db);
import _ "github.com/mattn/go-sqlite3"
db, _ := sql.Open("sqlite3", "hoge.db")
実は、このsqlite3_open()のfilename引数はパスだけではなく、file:/path/to/database.db
のようにURI形式で指定することも出来ます。この何が嬉しいかというと、クエリパラメータを指定できることです。sqliteはfilenameのクエリパラメータで、データベースの振る舞いをある程度設定することができます。
# ちなみにsqlite3_open_v2()だとconstで指定することもできる
クエリ | 例 | 意味 |
---|---|---|
vfs | データベースファイルで使用するVFSの名前を指定する。 カスタムしたVFSを指定すれば、例えば任意のFS内のDBを使うとかが出来るらしい。 |
|
mode | データベースの読み込みモードを指定する。 ro:ReadOnly, rw:Read-Write rwc:Read-Write(無ければCreate) memory:In-Memory |
file:test.db?mode=rw file:temporary?mode=memory
|
cache |
Shared-cache modeを使用するかを指定する。テーブルロックをコネクション間で共有することが出来るようになるっぽい。 shared:有効 private:無効 |
file:test.db?cache=shared |
psow |
Powersafe overwriteの有効状態を設定する。なんかディスクの消費電力量を下げるらしい。 1:有効 0:無効 |
|
nolock | データベースのファイルをロックするかを指定する。ロックをサポートしないファイルシステムではdisableが便利だとされているが、複数プロセスから書き込んだら壊れるのだろうし、ロックな人生向けっぽい。 1:有効 0:無効 |
|
immutable | 読み込んだデータベースファイルには変更を書き込まないモード。 1:有効 0:無効 |
file:test.db?immutable=1 |
sqliteでIn-Memory Database
sqliteはファイルベースのDBMSという印象が強いですが、RAMメモリ上にDBを展開する「In-Memory Database」という機能があります。プロセスを殺すとデータが揮発するので使いドコロは考えものですが動作はピカイチに早く、例えば一時的なデータ保持やモデルのユニットテストなどで便利な機能です。
In-Memory Databaseを使うときはよく:memory:
というDSNが使われますが、これはコネクションごとに新しいDBを作成するため、コネクションを明示的に扱わない高級レイヤーの上ではなかなかハマります。
# 僕はそういうハマり方をキッカケに、sqlite楽しくでドキュメント読み漁ってしまった感じです
たとえばGoだと、
import _ "github.com/mattn/go-sqlite3"
db, _ := sql.Open("sqlite3", ":memory:")
db.Exec(`CREATE TABLE TEST(id integer);`)
rows1, err := db.Query(`SELECT FROM TEST;`)
if err != nil {
panic(err)
}
rows2, err := db.Query(`SELECT FROM TEST;`)
if err != nil {
panic(err)
}
みたいな感じの呼び方をすると、rows1
がクローズされていないのでrows2
では新しいコネクションが生成されますが、新規なDBに接続してしまうためrows2
では意図に反して"No such table"エラーが返されてしまいます。
そこで、In-Memory DatabaseもURIで名前をつけてあげることにします。URIのmode
パラメータにはmemory
という指定ができますが、ここでfile:testdb?mode=memory
のように名前をつけてやることができます。(もちろんファイルには吐かれない)
こうすることでどのデータベースに接続するのかがハッキリしますから、複数コネクションになった時も意図したように動作するようになります。
感想
sqlite、シンプルなようで奥が深いのでドキュメント読んでると楽しい。
組み込みっぽい泥臭さもあってマツタケのようなDBだと思った。