提交 f5c0c7ff 编写于 作者: E Erol Fornoles

Introduce new ActiveRecord transaction error classes

上级 61483b18
......@@ -742,7 +742,7 @@ def translate_exception(exception, message)
when ER_DATA_TOO_LONG
ValueTooLong.new(message)
when ER_LOCK_DEADLOCK
TransactionSerializationError.new(message)
DeadlockDetected.new(message)
else
super
end
......
......@@ -407,6 +407,7 @@ def postgresql_version
FOREIGN_KEY_VIOLATION = "23503"
UNIQUE_VIOLATION = "23505"
SERIALIZATION_FAILURE = "40001"
DEADLOCK_DETECTED = "40P01"
def translate_exception(exception, message)
return exception unless exception.respond_to?(:result)
......@@ -419,7 +420,9 @@ def translate_exception(exception, message)
when VALUE_LIMIT_VIOLATION
ValueTooLong.new(message)
when SERIALIZATION_FAILURE
TransactionSerializationError.new(message)
SerializationFailure.new(message)
when DEADLOCK_DETECTED
DeadlockDetected.new(message)
else
super
end
......
......@@ -285,14 +285,24 @@ class ImmutableRelation < ActiveRecordError
class TransactionIsolationError < ActiveRecordError
end
# TransactionSerializationError will be raised when a transaction is rolled
# TransactionRollbackError will be raised when a transaction is rolled
# back by the database due to a serialization failure or a deadlock.
#
# See the following:
#
# * http://www.postgresql.org/docs/current/static/transaction-iso.html
# * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
class TransactionSerializationError < ActiveRecordError
class TransactionRollbackError < ActiveRecordError
end
# SerializationFailure will be raised when a transaction is rolled
# back by the database due to a serialization failure.
class SerializationFailure < TransactionRollbackError
end
# DeadlockDetected will be raised when a transaction is rolled
# back by the database when a deadlock is encountered.
class DeadlockDetected < TransactionRollbackError
end
# IrreversibleOrderError is raised when a relation's order is too complex for
......
......@@ -27,32 +27,25 @@ class Sample < ActiveRecord::Base
@connection.drop_table 'samples', if_exists: true
end
test "raises error when a serialization failure occurs" do
assert_raises(ActiveRecord::TransactionSerializationError) do
thread = Thread.new do
Sample.transaction isolation: :serializable do
Sample.delete_all
10.times do |i|
sleep 0.1
test "raises DeadlockDetected when a deadlock is encountered" do
assert_raises(ActiveRecord::DeadlockDetected) do
s1 = Sample.create value: 1
s2 = Sample.create value: 2
Sample.create value: i
end
thread = Thread.new do
Sample.transaction do
s1.lock!
sleep 1
s2.update_attributes value: 1
end
end
sleep 0.1
Sample.transaction isolation: :serializable do
Sample.delete_all
10.times do |i|
sleep 0.1
Sample.create value: i
end
sleep 0.5
Sample.transaction do
s2.lock!
sleep 1
s1.update_attributes value: 2
end
thread.join
......
......@@ -26,9 +26,9 @@ class Sample < ActiveRecord::Base
@connection.drop_table 'samples', if_exists: true
end
test "raises error when a serialization failure occurs" do
test "raises SerializationFailure when a serialization failure occurs" do
with_warning_suppression do
assert_raises(ActiveRecord::TransactionSerializationError) do
assert_raises(ActiveRecord::SerializationFailure) do
thread = Thread.new do
Sample.transaction isolation: :serializable do
Sample.delete_all
......@@ -51,8 +51,33 @@ class Sample < ActiveRecord::Base
Sample.create value: i
end
end
thread.join
end
end
end
test "raises DeadlockDetected when a deadlock is encountered" do
with_warning_suppression do
assert_raises(ActiveRecord::DeadlockDetected) do
s1 = Sample.create value: 1
s2 = Sample.create value: 2
thread = Thread.new do
Sample.transaction do
s1.lock!
sleep 1
s2.update_attributes value: 1
end
end
sleep 0.5
Sample.transaction do
s2.lock!
sleep 1
s1.update_attributes value: 2
end
thread.join
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册