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).
Related
if autocommit is on, which is default, postgresql treats each statement as a transaction.
so if i have an explicit transaction block with start transaction and commit, does that mean that block is not executed atomically and cannot be rolled back? (since each statement inside the block would be a transaction in itself due to autocommit).
It's the opposite.
With autocommit turned on, using start transaction is the only way to combine multiple statements into a single transaction.
In fact, Postgres always uses autocommit on the server, unless the client uses start transaction (or begin transaction). When you turn off auto-commit the client will simply send those statements for you automatically.
Quote from the manual
BEGIN initiates a transaction block, that is, all statements after a BEGIN command will be executed in a single transaction until an explicit COMMIT or ROLLBACK is given. By default (without BEGIN), PostgreSQL executes transactions in “autocommit” mode
(Emphasis mine)
BEGIN is the same as START TRANSACTION
Autocommit only affects statements outside of a transaciton. When you do your own start transaction and commit, autocommit has no effect.
When a statement is run outside a transaction, autocommit
ON means that means it is committed when it finishes
OFF means that a new transaction is implicitly started, and an explicit commit is required to commit the statement
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
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.
i have a loop while in sql which do something as it
begin tran one
do some inserts in others tables
--start loop
begin tran two
--do something
begin try
--if something fail then a trigger does rollback and this return a error (and this goes to catch), then don't i need do the rollbak in catch? this could not be dissable because this is working on production
--something finished ok
commit tran two
end try
begin catch
rollback tran two
end catch
--finished loop
commit
----------
i got this error
Uncommittable transaction is detected at the end of the batch. The
transaction is rolled back.
begin tran one
begin tran two
rollback tran two
doing this code i get this:
Cannot roll back two. No transaction or savepoint of that name was found.
I only want the subquery to rollback the second loop and continue with others records.
Operator rollback rolls back all transaction, for roll back only second loop you you must use savepoints:
begin tran one
-- do some inserts in others tables
--start loop
save tran two -- begin tran two
--do something
begin try
update product set id = 1 --if something fail then a trigger does rollback and this return a error (and this goes to catch), then don't i need do the rollbak in catch? this could not be dissable because this is working on production
--something finished ok
commit tran two
end try
begin catch
rollback tran two
end catch
--finished loop
commit
trigger example:
create table product (id int)
GO
create trigger product_trigger on product for update
as
set xact_abort off
if (select count(*) from inserted i join product p on i.id=p.id)=0 begin
if (##trancount>0) begin
/* rollback */
raiserror('product does not exist', 16, 1)
end
end
In my case, was my code was calling, thru an EF DbContext method, a SQL Server stored procedure, which contained a non-nested transaction.
Since, as #NotMe has already pointed-out, that "there is no such as a nested transaction in SQL Server", I began wondering whether my process was really transaction-nestingless.
Suspecting, that my DbContext had some guilt, I started checking on DbContext options, until DbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = True caught my attention.
So, as soon as I changed it value to True, everything worked successfully.
MyDbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
What happened?
Well, in my opinion, EF's ObjectContext.ExecuteFunction method was managing its own outer transaction as a wrapper to my stored procedure's inner transaction, so, when my stored procedure's ROLLBACK TRAN was hit, there was no pending transaction when EF's COMMIT/ROLLBACK code was hit.
Oddly enough, while gathering some references on EnsureTransactionsForFunctionsAndCommands property, I found that this default behaviour is due to one of the worst (in my opinion) EF team's decision ever, since it collides diretly with every ROLLBACK TRAN inside a T-SQL script.
For further details on EF, check insightfull SO's QA at EF6 wraps every single stored procedure call in its own transaction. How to prevent this?
Basically, everyone should check ##trancount > 0 before issuing a ROLLBACK command, whether named or not, specially inside stored procedure.
CREATE PROCEDURE Proc1 AS
BEGIN
BEGIN TRAN
EXEC Proc2
IF(##trancount > 0)
COMMIT TRAN
END
CREATE PROCEDURE Proc2 AS
BEGIN
BEGIN TRAN
ROLLBACK TRAN
END
For better awareness about Microsoft SQL Server's nested transactions, I would suggest reading the following article
Be careful using ROLLBACK on nested transaction in SQL Server!
Hope it helps someone :-)
Say I have a stored procedure consisting of several separate SELECT, INSERT, UPDATE and DELETE statements. There is no explicit BEGIN TRANS / COMMIT TRANS / ROLLBACK TRANS logic.
How will SQL Server handle this stored procedure transaction-wise? Will there be an implicit connection for each statement? Or will there be one transaction for the stored procedure?
Also, how could I have found this out on my own using T-SQL and / or SQL Server Management Studio?
Thanks!
There will only be one connection, it is what is used to run the procedure, no matter how many SQL commands within the stored procedure.
since you have no explicit BEGIN TRANSACTION in the stored procedure, each statement will run on its own with no ability to rollback any changes if there is any error.
However, if you before you call the stored procedure you issue a BEGIN TRANSACTION, then all statements are grouped within a transaction and can either be COMMITted or ROLLBACKed following stored procedure execution.
From within the stored procedure, you can determine if you are running within a transaction by checking the value of the system variable ##TRANCOUNT (Transact-SQL). A zero means there is no transaction, anything else shows how many nested level of transactions you are in. Depending on your sql server version you could use XACT_STATE (Transact-SQL) too.
If you do the following:
BEGIN TRANSACTION
EXEC my_stored_procedure_with_5_statements_inside #Parma1
COMMIT
everything within the procedure is covered by the transaction, all 6 statements (the EXEC is a statement covered by the transaction, 1+5=6). If you do this:
BEGIN TRANSACTION
EXEC my_stored_procedure_with_5_statements_inside #Parma1
EXEC my_stored_procedure_with_5_statements_inside #Parma1
COMMIT
everything within the two procedure calls are covered by the transaction, all 12 statements (the 2 EXECs are both statement covered by the transaction, 1+5+1+5=12).
You can find out on your own by creating a small stored procedure that does something simple, say insert a record into a test table. Then Begin Tran; run sp_test; rollback; Is the new record there? If so, then the SP ignores the outside transaction. If not, then the SP is just another statement executed inside the transaction (which I am pretty sure is the case).
You must understand that a transaction is a state of the session. The session can be in an explicit transaction state because there is at least one BEGIN TRANSACTION that have been executed in the session wherever the command "BEGIN TRANSACTION" has been throwed (before entering in a routine or inside the routine code). Otherwise, the state of the session is in an implicit transaction state. You can have multiple BEGIN TRANSACTION, but only the first one change the behavior of the session... The others only increase the ##TRANCOUNT global sesion variable.
Implicit transaction state means that all SQL orders (DDL, DML and DCL comands) wil have an invisble integrated transaction scope.