PostgreSQL トランザクションの隔離性
PostgreSQL のトランザクションで使用できる隔離性 isolation level は, read committed と, serializable の 2 種類です. これらは, それぞれ, 文単位での読み取り一貫性と, トランザクション単位での読み取り一貫性を保証しようとするものです. 1
さて, 以下のようなテーブル m があります.
mydb=# select * from m; m_id | m_name | m_upd_time ------+--------+------------ 1 | foo | 2 | bar | 3 | baz | (3 rows)
ここに, 以下のようなタイミングで, 2 つのトランザクション, Trans1, Trans2 を実行します.
Time | Trans1 | Trans2 |
---|---|---|
1 | select from m | - |
2 | - | update m |
3 | select from m | - |
すると, それぞれの隔離性に対して, 以下の実行結果が得られます.
------- Read Committed Isolation Level begin trans2 end trans2 begin trans1 begin select trans1:bar end select begin trans2 end trans2 begin select trans1:fizzbuzz end select end trans1 ------- Serializable Isolation Level begin trans2 end trans2 begin trans1 begin select trans1:bar end select begin trans2 end trans2 begin select trans1:bar end select end trans1
なお, 各隔離性の実行結果について, 先頭の Trans2 の実行は無視してください. テーブル値の初期化に使用しています.
以下は, 実験に使用したソースコード.
### ### pg-trans1.rb ### require 'rubygems' require 'pg' class PgTrans def initialize(*conn) @conn = PGconn.open(*conn) end def x(sql, *rest) @conn.exec(sql, *rest) end private :x end class Trans1 < PgTrans def execute(is_serial = false) begin puts 'begin trans1' x 'begin' x 'set transaction isolation level serializable' if is_serial puts 'begin select' r = x 'select * from m where m_id = 2' r.each {|t| puts "trans1:#{t['m_name']}" } puts 'end select' sleep 0.2 puts 'begin select' r = x 'select * from m where m_id = 2' r.each {|t| puts "trans1:#{t['m_name']}" } puts 'end select' x 'commit' puts 'end trans1' rescue x 'rollback' STDERR.puts "pg:#$!" end end end class Trans2 < PgTrans def execute(mname) begin puts 'begin trans2' x 'begin' x "update m set m_name = $1 where m_id = 2", [mname] x 'commit' puts 'end trans2' rescue x 'rollback' STDERR.puts "pg:#$!" end end end def go_trans(is_serial) Trans2.new(:dbname => 'mydb').execute('bar') threads = [] threads. push(Thread.new() do Trans1.new(:dbname => 'mydb').execute(is_serial) end ) threads. push(Thread.new() do Trans2.new(:dbname => 'mydb').execute('fizzbuzz') end ) threads.each {|t| t.join } end puts '------- Read Committed Isolation Level' go_trans(false) puts '------- Serializable Isolation Level' go_trans(true)
1. 完全に保証するわけではない. 13.2.2.1. Serializable Isolation versus True Serializability, PostgreSQL 8.4.2 Documentation
| 固定リンク
| コメント (0)
| トラックバック (0)