SQLServer вопрос

chekur13
Новичок
Posts: 30
Joined: 09 Feb 2002 10:01
Location: Kharkov, Ukraine

SQLServer вопрос

Post by chekur13 »

Разбирались с одной задачкой из теста и обнаружили странное поведение двух, казалось бы одинаковых кусков кода

Code: Select all


begin transaction mytran2

select @@trancount

begin transaction mytran1

select @@trancount

rollback transaction mytran1

select @@trancount

commit transaction mytran2

select @@trancount

rollback



В этом случае возникает ошибка, остается брошенной транзакция, на мой взгляд поведение ожидаемое (не учитывая брошенную транзакцию)

Code: Select all

Server: Msg 6401, Level 16, State 1, Line 10
Cannot roll back mytran1. No transaction or savepoint of that name was found.


Тот же кусок кода, только изменено имя mytran2 на mytran

Code: Select all


begin transaction mytran

select @@trancount

begin transaction mytran1

select @@trancount

rollback transaction mytran1

select @@trancount

commit transaction mytran

select @@trancount



Ошибка уже другая

Code: Select all

Server: Msg 3902, Level 16, State 1, Line 14
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.


Кто-нибудь может прокомментировать подобное поведение???
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Post by Dmitry67 »

Забавно
Эксперимент показал что важно чтобы имя одной транзакции 'содержалось' в имени другой
Причем это case-sensitive даже на case-insensitive базе, то есть явно strcmp :)
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
vc
Уже с Приветом
Posts: 664
Joined: 05 Jun 2002 01:11

Re: SQLServer вопрос

Post by vc »

chekur13 wrote:Разбирались с одной задачкой из теста и обнаружили странное поведение двух, казалось бы одинаковых кусков кода

Code: Select all


begin transaction mytran2

select @@trancount

begin transaction mytran1

select @@trancount

rollback transaction mytran1

select @@trancount

commit transaction mytran2

select @@trancount

rollback



В этом случае возникает ошибка, остается брошенной транзакция, на мой взгляд поведение ожидаемое (не учитывая брошенную транзакцию)

Code: Select all

Server: Msg 6401, Level 16, State 1, Line 10
Cannot roll back mytran1. No transaction or savepoint of that name was found.


Тот же кусок кода, только изменено имя mytran2 на mytran

Code: Select all


begin transaction mytran

select @@trancount

begin transaction mytran1

select @@trancount

rollback transaction mytran1

select @@trancount

commit transaction mytran

select @@trancount



Ошибка уже другая

Code: Select all

Server: Msg 3902, Level 16, State 1, Line 14
The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.


Кто-нибудь может прокомментировать подобное поведение???


Sometimes it's useful to read the manual:

"Committing inner transactions is ignored by Microsoft® SQL Server™.
The transaction is either committed or rolled back based on the action taken at the end of the outermost transaction.
If the outer transaction is committed, the inner nested transactions are also committed.
If the outer transaction is rolled back, then all inner transactions are also rolled back,
regardless of whether or not the inner transactions were individually committed.

Each call to COMMIT TRANSACTION or COMMIT WORK applies to the last executed BEGIN TRANSACTION.
If the BEGIN TRANSACTION statements are nested, then a COMMIT statement applies only to the last nested transaction, which is the innermost transaction.
Even if a COMMIT TRANSACTION transaction_name statement within a nested transaction refers to the transaction name of the outer transaction, the commit applies only to the innermost transaction.

It is not legal for the transaction_name parameter of a ROLLBACK TRANSACTION statement to refer to the inner transactions of a set of named nested transactions.
transaction_name can refer only to the transaction name of the outermost transaction.
If a ROLLBACK TRANSACTION transaction_name statement using the name of the outer transaction is executed at any level of a set of nested transactions,
all the nested transactions are rolled back.
"

and

""Naming multiple transactions in a series of nested transactions with a transaction name has little effect on the transaction. Only the first (outermost) transaction name is registered with the system. A rollback to any other name (other than a valid savepoint name) generates an error. None of the statements executed before the rollback are in fact rolled back at the time this error occurs. The statements are rolled back only when the outer transaction is rolled back.
"


VC
chekur13
Новичок
Posts: 30
Joined: 09 Feb 2002 10:01
Location: Kharkov, Ukraine

Post by chekur13 »

Покажите мне пожалуйста строку в мануале, в которой написано, что в зависимости как вы назовете транзакцию, такое и будет поведение. Первый и второй сценарии по коду различаются ТОЛЬКО именем внешней транзакции, в результате иы имеем различное поведение.
vc
Уже с Приветом
Posts: 664
Joined: 05 Jun 2002 01:11

Post by vc »

chekur13 wrote:Покажите мне пожалуйста строку в мануале, в которой написано, что в зависимости как вы назовете транзакцию, такое и будет поведение. Первый и второй сценарии по коду различаются ТОЛЬКО именем внешней транзакции, в результате иы имеем различное поведение.


My point is that you are incorrectly using the rollback statement. It can contain the name of the outermost transaction only, otherwise SQL Server should generate an error.

If you say that in the second case Sql Server misbehaves, then you are right. It's probably a bug and the same error, as in the first case, should have been generated.

VC
vc
Уже с Приветом
Posts: 664
Joined: 05 Jun 2002 01:11

Post by vc »

vc wrote:
chekur13 wrote:Покажите мне пожалуйста строку в мануале, в которой написано, что в зависимости как вы назовете транзакцию, такое и будет поведение. Первый и второй сценарии по коду различаются ТОЛЬКО именем внешней транзакции, в результате иы имеем различное поведение.


My point is that you are incorrectly using the rollback statement. It can contain the name of the outermost transaction only, otherwise SQL Server should generate an error.

If you say that in the second case Sql Server misbehaves, then you are right. It's probably a bug and the same error, as in the first case, should have been generated.

VC


Forgot to mention (in case it's not obvious) that in the second case the rollback acts as if it were 'rollback mytran'. That's why you are getting a different error message ('beging mytran' was matched, incorrectly, with 'rollback mytran1').
User avatar
tengiz
Уже с Приветом
Posts: 4468
Joined: 21 Sep 2000 09:01
Location: Sammamish, WA

Post by tengiz »

Это "странность" SQL Server 2000 и Yukon (SQL Server 7.0 и старше работают как ожидается.) Проблема, как уже сказали коллеги, в сравнении строк по минимальной длине. Соответственно если одна строки совпадает с началом другой - мы имеем то, что Вы видели. Смешной side-effect заключается в том, что если начать транзакцию без имени (длина имени 0), то любая строка в ROLLBACK окажется совпадением. Забавно, что в отличие от автора вопроса эту проблему в SQL Server 2000 никто до сих не обнаружил - ни тестеры, ни пользователи. Что лично я могу объяснить только одним - многоуровневые именованные пользовательские транзакции (кроме именованных SAVEPOINT - а вот в этом случае сравнение имён уже строгое) в SQL Server вообще-то малополезны и практически не используются. Теперешний владелец этого кода в курсе проблемы, однако полагал, что это унаследованное недокументированное поведение (которое во многих случаях не исправляется, особенно когда есть основания считать, что пользователи несмотря на отсутствие явного обещания в документации на такое поведение тем не менее рассчитывают,) поэтому и не пытался его исправить.

Так что спасибо за вопрос.
Cheers
chekur13
Новичок
Posts: 30
Joined: 09 Feb 2002 10:01
Location: Kharkov, Ukraine

Post by chekur13 »

Спасибо, Тенгиз, за объяснение. Конечно же я сам не пользуюсь именоваными транзакциями (за исключением SAVEPOINTS), вопрос этот всплыл после сдачи теста на BrainBench одним моим сотрудником. Вопрос звучал так

Code: Select all

 
 
 Sample Code 
 A. begin transaction trx1
B. ... Code ...
C. begin transaction trx2
D. rollback transaction trx2
E. ... Code ...
F. commit transaction trx1 
  What happens if the code above is executed? 
 


В результате и была обнаружена вышеупомянутая проблема
[/code]
Call
Уже с Приветом
Posts: 101
Joined: 17 Jun 2003 04:41

Post by Call »

SQL или откатывает всю транзакцию c вложенными транзакциями или завершает ее. Нельзя откатить транзакцию внутри открвтой
транзакции, в этом случае не бедет поддерживаться целостность данных.

Поэтому после begin transaction mytran1 у вы можете только откатить транзакцию
mytran2 с mytran1

Code: Select all

begin transaction mytran2 

select @@trancount

begin transaction mytran1

select @@trancount

rollback transaction 

select @@trancount 


It is not legal for the transaction_name parameter of a ROLLBACK TRANSACTION
statement to refer to the inner transactions of a set of named nested
transactions. transaction_name can refer only to the transaction name of the
outermost transaction.

Return to “Вопросы и новости IT”