H2、Derby、SQLiteの仕様の調査メモ(ロック周り)

はじめに

 軽量DBのロック周りを話題にする人はあまりいません。
 並列度が高い状態で使うことは稀であり、ロック周りはわりとどうでも良いことだと私も思います。でも、気になって気になって仕方ないので軽く調査しました。

調査対象

 私がたまたま名前を知っていたものを調査することに決めました。

  • H2 Database Engine 1.0.79
  • Apache Derby 10.4.2.0
  • SQLite 3.6.4


ロックの粒度

 狙ったわけではないのですが、見事にばらばら。

H2

 デフォルトはテーブル全体です。行レベルロックは未サポート。ベータ版ならば、行レベルロックもサポートしてる模様。
 (Features -> Comparison to Other Database Enginesより)

Derby

 デフォルトは行ロックです。ただし、特定のトランザクションについては、Derbyがパフォーマンスの上の理由でロック粒度を複数行ロック、テーブルロックに拡大するかもしれません。(いわゆるロックエスカレーション)
 行ロックを使用しない設定も可能です。(常にテーブルロックを使用するということ)
 (Derby Developer's Guide -> Controlling Derby application behavior -> Locking, concurrency, and isolation -> Lock granularity より)

SQLite

 デフォルトはDB全体です。ロック粒度の変更は不可能。
 (Appropriate Uses For SQLite -> Situations Where Another RDBMS May Work Better -> High Concurrencyより)

ロック種別

 共有ロックと排他ロックが別物として存在していますので、どのDBもロックの種別について、似ていると言えば似てます。

H2
排他ロック データ変更中に獲得されるロックです。他のトランザクションによるロックの獲得は待ち状態になります。
共有ロック 変更を伴わないデータ読み込み時に獲得されるロックです。他のトランザクションによる共有ロックは、排他ロック獲得待ちトランザクションが居ない場合に獲得できます。
他のトランザクションから排他ロック獲得要求が会った場合、共有ロックが全て解除されるまで、要求をしたトランザクションは待ち状態になります。

 (Multiple Connections ->Locking, Lock-Timeout, Deadlocksより)
 排他ロック獲得待ちの状態を、ロックの一種扱いしないのですね。

Derby
排他ロック データ変更中に獲得されるロックです。他のトランザクションによるロックの獲得は許されません。
共有ロック 変更を伴わないデータ読み込み時に獲得されるロックです。他のトランザクションの共有ロック、更新ロックは許可します。排他ロックは許可しません。
更新ロック 更新可能カーソル使用時に獲得されるロックです。実際にデータ更新を行う際には排他ロックの獲得を試みます。他のトランザクションの共有ロックは許可します。排他ロック、更新ロックは許可しません。

 (Derby Developer's Guide -> Controlling Derby application behavior -> Locking, concurrency, and isolation -> Types and scope of locks in Derby systems より)
 更新ロックの仕様が個人的に驚きです。ずっと更新できない可能性が存在しそうですが。資料の解釈間違っていないか不安。

SQLite
排他ロック データ変更中に獲得されるロックです。他のトランザクションによるロックの獲得は許されません。
共有ロック 変更を伴わないデータ読み込み時に獲得されるロックです。他のトランザクションの共有ロック、PENDINGロック獲得は許可します。排他ロックは許可しません。
予約ロック 書き込みを行いたいが、既に共有ロックが獲得されている場合に獲得されます。
他のトランザクションの共有ロックは許可します。予約ロック、PENDINGロック、排他ロックは許可されません。
PENDINGロック 書き込みを行いたいが、既に共有ロックが獲得されている場合に獲得されます。
可能な限り早く書き込みたい場合に使用されます。予約ロックとは異なり、共有ロックの獲得も許可しません。

 (File Locking And Concurrency In SQLite Version 3 -> 3.0 Locking より)
 PENDINGロックは日本語で何というのでしょうか。

分離レベル

 サポートしている分離レベルです。Derbyだけちょっと本気出して種別を用意してます。

H2
分離レベル デフォルト
TRANSACTION_READ_UNCOMMITT
TRANSACTION_READ_COMMITTED
TRANSACTION_SERIALIZABLE

 (Advanced Topics -> Transaction Isolationより)

Derby
分離レベル デフォルト
TRANSACTION_READ_UNCOMMITT
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE

 (Controlling Derby application behavior -> Locking, concurrency, and isolation -> Isolation levels and concurrencyより)

SQLite

 SQLiteのページには、一般的な分離レベルでの表記がありません。
 トランザクション開始直後にロックをどのように獲得するか、という表現で記述されています。
 「JDBCの分離レベルで表現するとこういうこと?」というのをメモとして併記しておきます。

分離レベル デフォルト 説明 JDBCで言うと?
DEFERRED
トランザクション開始直後にはロックを獲得しません。 TRANSACTION_READ_COMMITTED
IMMEDIATE トランザクション開始直後に、予約ロックを獲得します。 TRANSACTION_REPEATABLE_READ
EXCLUSIVE トランザクション開始直後に、排他ロックを獲得します。 TRANSACTION_SERIALIZABLE

 (SQL Syntax -> BEGIN TRANSACTIONより)

(おまけ)ライセンス

 おまけでライセンスです。私にはよくわかりませんけど、メモ。

H2

MPL 1.1 or EPL 1.0
(license.html より)

Derby

The Apache License, Version 2.0
(Getting Started with Derby ->Licenseより)

SQLite

Public domain
(Distinctive Features ->Public domain)

最後に

 あまり上手くまとまらないですが、あえてまとめると下記のようになります。

  • デフォルトはどれもTRANSACTION_READ_COMMITTED
  • ロックの粒度はばらばら
  • OracleみたいにSELECT時にUNDO領域から読むタイプは無い