Sql Transaction doesn't release lock after commit - sql

I have run a script similar to the one below in a SSMS query window. After the script run successfully, some locks remained on affected tables. When I try to close the window, a messagebox is showed asking me if I want to commit or cancel the transaction.
After I choose one of the options, the locks are released.
What can cause this behaviour?
begin tran
delete from tableA
delete from tableB
insert into tableB
insert into tableA
commit tran
I'm connected to a remote Sql Server 2014 and running localy SSMS 2014
Thanks!

The following example illustrates how locks are not released as a result of an unfinished open transaction:
Open the SQL Server Query Analyzer and run the following batch but cancel the transaction before it completes:
Begin Tran
Update authors set state = 'CA'
waitfor delay "00:02:00" --Cancel the command
Commit Tran
View the locks that are held by executing the following command:
sp_lock
You see that locks are held for the authors table.
From the same server process id (SPID), execute the next batch:
Begin Tran
Update titleauthor set au_ord = 0
Commit Tran - Completed transaction.
View the locks that are held by executing the following command:
sp_lock
You see that although the last transaction is completed, locks are held on both the authors and titleauthors tables. The reason is that the first transaction did not complete and when the second transaction was executed from the same connection, it was treated as a nested transaction.
You can view the transaction count by checking the ##trancount global variable by issuing the following statement:
select ##trancount
This query returns 1, which indicates that one transaction is outstanding.
Any further transactions that are executed from this connection are treated as nested. Locks continue to accumulate and are not released until a ROLLBACK is executed, which rollbacks to the outer most transaction or to a savepoint.
In continuing with the example, you can see how a rollback may cause a completed transaction to be negated by executing the following transaction from the same connection:
Begin Tran
Update titles set royalty = 0
Rollback
The rollback rolls the batch back to the outermost transaction, even though there is a completed transaction (2) on titleauthors. The rollback on the completed transaction occurs because the completed transaction is treated as a nested transaction.
To avoid this kind of problem, check after each transaction to see if the transaction is complete by using the following statement:
If ##trancount > 0 rollback
Reference: Incomplete transaction may hold large number of locks and cause blocking

Related

Where is the flaw in my trigger to override DELETE with a soft-delete?

I have a trigger created with
CREATE TRIGGER [CantDeleteStuff] ON [dbo].[Stuff]
INSTEAD OF DELETE
AS
BEGIN
ROLLBACK
UPDATE [dbo].[Stuff] SET [Deleted]=1 FROM DELETED WHERE [dbo].[Stuff].[Id] = DELETED.[Id]
END
GO
and I think it's intent is clear. But when I try to delete a row I get the error
The transaction ended in the trigger. The batch has been aborted.
How to fix?
Instead of Delete will replace the Delete with your triggering code.
According to Technet, the Rollback in your trigger is the issue. You can read more here.
A trigger operates as if there were an outstanding transaction in effect when the trigger is executed. This is true whether the statement firing the trigger is in an implicit or explicit transaction.
When a statement begins executing in autocommit mode, there is an implied BEGIN TRANSACTION to allow the recovery of all modifications generated by the statement if it encounters an error. This implied transaction has no effect on the other statements in the batch because it is either committed or rolled back when the statement completes. This implied transaction is still in effect, however, when a trigger is called.
When a trigger executes, an implicit transaction is started. If the trigger completes execution and ##TRANCOUNT = 0, error 3609 occurs and the batch is terminated. If a BEGIN TRANSACTION statement is issued in a trigger, it creates a nested transaction. In this situation, when a COMMIT TRANSACTION statement is executed, the statement will apply only to the nested transaction.
When using ROLLBACK TRANSACTION in a trigger, be aware of the following behavior:
All data modifications made to that point in the current transaction are rolled back, including any that were made by the trigger.
The trigger continues executing any remaining statements after the ROLLBACK statement. If any of these statements modify data, the modifications are not rolled back.
A ROLLBACK in a trigger closes and deallocates all cursors that were declared and opened in the batch containing the statement that fired the trigger. This includes cursors declared and opened in stored procedures called by the batch that fired the trigger. Cursors declared in a batch prior to the batch that fired the trigger are only closed. However, STATIC or INSENSITIVE cursors are left open if:
CURSOR_CLOSE_ON_COMMIT is set OFF.
The static cursor is either synchronous or a fully populated asynchronous cursor.
Instead of using ROLLBACK TRANSACTION, the SAVE TRANSACTION statement can be used to execute a partial rollback in a trigger.
https://technet.microsoft.com/en-us/library/ms187844(v=sql.105).aspx
So just remove the Rollback.

What's the difference between begin transaction vs. begin work

I saw in SQL Server about the transaction part it has following statements:
begin transaction or begin work
commit transaction or commit work
rollback transaction or commit work
I used transaction set statements in my work, but why there are work statements here?
Are they same? If not, what the difference between them?
According to Microsoft's SQL Server documentation, there is no support for BEGIN WORK, instead use BEGIN TRANSACTION (which also supports named transactions).
The token BEGIN (by itself) denotes a statement-block and is completely unrelated to transactions.
Curiously, while SQL Server does not support BEGIN WORK, SQL Server does support COMMIT WORK and ROLLBACK WORK.
COMMIT WORK has identical semantics to COMMIT TRANSACTION.
ROLLBACK WORK has identical semantics to ROLLBACK TRANSACTION.
Also curiously, [the ISO SQL-2016][6] grammar uses START TRANSACTION with COMMIT WORK and ROLLBACK WORK which is a strangely inconsistent use of language keywords.
SQL Server 2017+ and Azure SQL does seem to support START WORK though SSMS does not recognize the syntax.
ISO SQL (2016) vs T-SQL (MS SQL Server)
ISO SQL
T-SQL (SQL Server)
Effect on ##TRANCOUNT
Transactions
Begin a transaction
START TRANSACTION
BEGIN TRANSACTION
+ 1
Commit a transaction
COMMIT WORK
COMMIT TRANSACTION
- 1
Rollback a transaction
ROLLBACK WORK
ROLLBACK TRANSACTION
= 0
Savepoints
Create a savepoint
SAVEPOINT
SAVE TRANSACTION
(No effect)
Release a savepoint
RELEASE SAVEPOINT
(Not supported)
(No effect)
Rollback to savepoint
ROLLBACK WORK TO SAVEPOINT
ROLLBACK TRANSACTION
(No effect)
Syntax Support in SQL Server 2016 and later, and Azure SQL
NOTE: This does not necessarily include Azure Synapse, SQL Server Parallel Data Warehouse, and Analytics Platform System.
T-SQL Syntax
Semantics
Similar and Ambiguous syntax:
These commands are easily confused for TRANSACTION control statements, but in SQL Server are completely unrelated to TRANSACTIONS.
BEGIN
BEGIN, by itself, without any following TRAN or TRANSACTION keyword, denotes a statement block terminated by END.
START
Undocumented, but recognized by SSMS, curiously.
Start a transaction:
BEGIN WORK
Not supported by SQL Server
START WORK
Not supported by SQL Server
START TRANSACTION
Not supported by SQL Server
BEGIN TRAN
Identical to BEGIN TRANSACTION
BEGIN TRAN <transaction_name>
Identical to BEGIN TRANSACTION <transaction_name>. transaction_name can also be a #variable containing the transaction name. Named transactions are mostly used with nested transactions, but committing an inner transaction is a NOOP and only the outermost transaction can be used with ROLLBACK
BEGIN TRANSACTION
Starts an unnamed transaction.
BEGIN TRANSACTION <transaction_name>
transaction_name can also be a #variable containing the transaction name.
Commit a transaction
COMMIT
Identical to COMMIT TRANSACTION
COMMIT WORK
Identical to COMMIT TRANSACTION. ISO SQL compliant.
COMMIT TRAN
Identical to COMMIT TRANSACTION
COMMIT TRAN <transaction_name>
Identical to COMMIT TRANSACTION <transaction_name>. transaction_name can also be a #variable containing the transaction name.
COMMIT TRANSACTION
Commits an unnamed transaction started with BEGIN TRANSACTION. Cannot be used to create a savepoint (use SAVE TRANSACTION for that).
COMMIT TRANSACTION <transaction_name>
Commits a named transaction started with BEGIN TRANSACTION <transaction_name>. Cannot be used to create a savepoint (use SAVE TRANSACTION <savepoint_name> for that). Committing a nested transaction is a no-op in SQL Server: inner/nested changes are only committed when the outermost transaction is committed.
Rollback a transaction
ROLLBACK
Identical to ROLLBACK TRANSACTION.
ROLLBACK WORK
Identical to ROLLBACK TRANSACTION. ISO SQL compliant.
ROLLBACK TRAN
Identical to ROLLBACK TRANSACTION.
ROLLBACK TRAN <transaction_name>
Identical to ROLLBACK TRANSACTION <transaction_name>. transaction_name can also be a #variable containing the transaction name.
ROLLBACK TRAN <savepoint_name>
Identical to ROLLBACK TRANSACTION <savepoint_name>. savepoint_name can also be a #variable containing the savepoint name.
ROLLBACK TRANSACTION
Rolls back the current explicit or implicit transaction.
ROLLBACK TRANSACTION <transaction_name>
Rolls back a named transaction. transaction_name must be the outermost transaction's name when working with nested transactions.
ROLLBACK TRANSACTION <savepoint_name>
savepoint_name must have been previously created with SAVE TRANSACTION <savepoint_name> (this is how the ROLLBACK TRANSACTION command for transactions vs. savepoints is disambiguated).

How to return back in SQL statement

I have run SQL server command (update command).
the command has been performed successfully and the table has been updated
is there any way to take back in that command ?
note: no backup taken
If you had originally asked the question how do I do an UPDATE with the possibility of ROLLBACK I would tell you you should do your ad-hoc updates like this.
BEGIN TRANSACTION
UPDATE blah
SET value = newvalue
WHERE condition = someothervalue
--COMMIT TRANSACTION
Then if the results are as expected run the COMMIT TRANSACTION. If they are not than you could do a ROLLBACK TRANSACTION. However since you already did the updates and have no backups or recovery plan you are pretty much out of luck.
After you have already executed an update command the only way back would be via restoring a backup.
Something I do when writing any modification scripts is to wrap the command in a transaction and then either run a rollback or a commit depending on if the query performed as suspected.
Example:
--start the transaction only execute the first three lines, this leaves the transaction open
BEGIN TRANSACTION
UPDATE TABLEA
SET COL1 = "newValue"
--examine data and based on the results run one of these two lines
ROLLBACK TRANSACTION
COMMIT TRANSACTION

When do I have to commit?

I heard in SQL I do not have to commit every statement. Perhaps create I don't have to.
So can you answer me which Statements I have to commit?
I read, that I have to commit all transactions, but I don't know what this is and can't find it anywhere.
Thanks for your help.
Per the SQL standard, most statements that require a transaction will automatically open one.
Some database engines, such as SQL Server, will (by default) automatically commit the transaction if the statement completes successfully. See Autocommit Transactions.
Autocommit mode is the default transaction management mode of the SQL Server Database Engine. Every Transact-SQL statement is committed or rolled back when it completes
SQL Server also has an Implicit Conversions mode which will leave the transaction open until it's explicitly commited.
When operating in this second such mode (which is the default, I believe, for Oracle), or if you've explicitly created a transaction, it's up to you as a developer when to commit the transaction. It should be when you've accomplished a "complete" set of operations against the database.
If you BEGIN a transaction then you have to either ROLLBACK or COMMIT
Example:
BEGIN TRAN
--Your code
INSERT INTO
NewTable
SELECT *
FROM TABLE
COMMIT TRAN
If you do not use that, it is committed upon execution. So the follow will either fail or be committed:
INSERT INTO
NewTable
SELECT *
FROM Table
If there is an error (like there is no NewTable in the DB) the execution will raise an error and the transaction will roll back. If there is no error the transaction will be committed.

Does a transaction affect all queries?

I started a transaction using BEGIN TRANSACTION in Management Studio but I forgot to ROLLBACK or COMMIT it for about 10 minutes. I freaked out and went back to ROLLBACK my changes. Did this rollback all queries that went through the server during that time or just through my user/connection?
Just your connection :-)
(Edit: rather your transaction, since the BEGIN TRANSACTION. If you did updates before the BEGIN TRANSACTION in the same session, they will of course not be rolled back)
BUT: It could have given SELECTs of other sessions the wrong answer depending on what lock types and query hints that were being used...
An example:
In one SQL Studio session, do the following:
CREATE TABLE a(a INT)
INSERT INTO a VALUES(1)
BEGIN TRANSACTION
UPDATE a
SET a = 2
SELECT *, ##TRANCOUNT
FROM a
-> You will see '2, 1' as result
Open a new session (tab in Sql studio)
Do:
SELECT *, ##TRANCOUNT
FROM a (NOLOCK)
You will see '2, 0'
Now, in first session, do
ROLLBACK TRANSACTION
SELECT *, ##TRANCOUNT
FROM a
-> transaction rolled back, and you see '1, 0'
-> a select in second session will also show '1, 0'
so: If you use (NOLOCK) hint, you can get uncommitted data as result -> which might lead to very unexpected effects :-)
Dont forget:
DROP TABLE a
when you're done ;)
It should only affect your transaction, so only things that were done in your session during that time.
You're fine. All the other queries will go through just fine.
It should roll back all queries made in the transaction, so it is more specific than your user\connection and definitely not all queries on the box.
You need to review the ACID properties of transactions. You see that there is nothing to worry about if a transaction is rolled back or committed it has no effect on the outcome of other transactions.
Your rollback affects only your transaction. The I in ACID.
However, the rows, pages or whole table you locked will affect other users if they want to use them. It depends on:
what they want to do
lock timeout
client command timeout