mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #25107 from Erol/introduce-new-ar-transaction-error-classes
Introduce new ActiveRecord transaction error classes Closes #26018
This commit is contained in:
commit
fac9938b91
5 changed files with 57 additions and 26 deletions
|
@ -753,7 +753,7 @@ module ActiveRecord
|
|||
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 @@ module ActiveRecord
|
|||
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 @@ module ActiveRecord
|
|||
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 @@ module ActiveRecord
|
|||
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 < StatementInvalid
|
||||
class TransactionRollbackError < StatementInvalid
|
||||
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 @@ module ActiveRecord
|
|||
@connection.drop_table 'samples', if_exists: true
|
||||
end
|
||||
|
||||
test "raises error when a serialization failure occurs" do
|
||||
assert_raises(ActiveRecord::TransactionSerializationError) do
|
||||
test "raises DeadlockDetected when a deadlock is encountered" do
|
||||
assert_raises(ActiveRecord::DeadlockDetected) do
|
||||
s1 = Sample.create value: 1
|
||||
s2 = Sample.create value: 2
|
||||
|
||||
thread = Thread.new do
|
||||
Sample.transaction isolation: :serializable do
|
||||
Sample.delete_all
|
||||
|
||||
10.times do |i|
|
||||
sleep 0.1
|
||||
|
||||
Sample.create value: i
|
||||
end
|
||||
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
|
||||
|
||||
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
|
||||
|
|
|
@ -26,9 +26,9 @@ module ActiveRecord
|
|||
@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 @@ module ActiveRecord
|
|||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue