54
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

sqlite3のDSN(filename)いろいろ

Last updated at Posted at 2015-03-09

ちょっとした理由でsqliteについて調べていました。そこで、sqliteでデータベースを指定するDSN(ドキュメント上はfilename)はファイル名や":memory:"だけでなくいろんな設定ができるようだったので、メモします。

sqlite3のDSN(filename)はURIにできる

sqliteの"filename"は、典型的にはファイル名を指定することが多いかと思います。たとえばhoge.dbにデータベースを保存している場合は、単純にこのファイルへのパスを渡すわけですね。

in_c.c
sqlite3_open("hoge.db", &db);
in_golang.go
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だと思った。

54
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?