 
 
SQLite の排他制御の動作が不思議だったので、検証コードを作ってテストした。
片方が transation 中に、もう片方がアクセスすると SQLite3::BusyException になる。( その時は retry はしていなかった。)
busy_timeout(5000) を指定しても効いて無いように見える。
require 'rubygems'
require 'sqlite3'
DBfile = "./test.db"
unless File.exist?( DBfile )
  db = SQLite3::Database.new(DBfile )
  sql = <<EOS
create table  data (
    id        integer  primary key,
    name      text
);
EOS
  db.execute_batch(sql)
  db.close()
end
0.upto( 100 ) do |n|
  db = SQLite3::Database.new(DBfile )
  ecount = 0
  begin
    db.busy_timeout(5000)
    db.transaction do
      STDERR.print(".")
      STDERR.flush()
      db.execute("insert into data ( name ) values ( ? )", n )
      rand(11).downto( 0 ) do |n|
        STDERR.print("-")
        STDERR.flush()
        sleep(1)
      end
    end
  rescue SQLite3::BusyException
    STDERR.print("*")
    STDERR.flush()
    if ecount > 10
      print ">SQLite3::BusyException\n"
      exit
    end
    ecount += 1
    sleep(1)
    retry
  rescue => e
    p $!
    exit
  end
  db.close()
  STDERR.print("\n")
  STDERR.flush()
  sleep( 1 )
end
コンソールを 2つ開き、同じディレクトリで上記のプログラムを実行する。
.-----
.*.----------
.*.*.-
.*.*.----
.*.-----------
.*.*.-
.*.-----------
.*.--------
.*.*.--
.*.*.-------
.*.-----
.*.*.-
.*.-
.*.-
.*.*.-----
.*.----------
何故か transaction が競合すると、
1回目は busy_timeout(5000) は効かず例外が起きる。
その後 rerty すると有効になる。
ただし FreeBSD の SQLite3.7.3 は一発目からちゃんと待つ。
待たないのは Linux の SQLite 3.3.6
なので、いずれにせよちゃんと retry してやれば、transaction      
でもアクセスの競合を防ぐ排他制御が可能