Transactions enable users to create T-SQL batch
statements that are either completely applied or do nothing to the
existing data. When changes are applied, it is said that the
transaction has committed. When the batch is stopped for any reason, such as by an error or being intentionally canceled, the transaction will be rolled back, and changes made within the transaction will not be made to the data.
Executing Transactions
The following example shows how to begin a
transaction, execute some statements, and then commit the transaction.
The example swaps the names of the two pets, Lady and Deno:
BEGIN TRANSACTION
UPDATE Pets SET pet_name='Lady' WHERE pet_id=3
UPDATE Pets SET pet_name='Deno' WHERE pet_id=2
COMMIT
Notice that the two UPDATE
statements are bracketed by the statements BEGIN TRANSACTION
and COMMIT
. These two UPDATE
statements form a transaction. Either they will both succeed or they
will both fail. And if they succeed, they will both appear to other
database users to have executed simultaneously. No other user but you
will ever see both pets having the same name of Lady. You, as the
person executing the transaction, are the only user with the ability to
query the intermediate state between the two UPDATE
statements. We’ll talk more about this in the “Isolating Transactions” section.
If you are executing a transaction and change your mind or make a mistake, you can issue a ROLLBACK
statement to undo the damage, for example:
BEGIN TRANSACTION
DELETE FROM Pets
ROLLBACK
This example deletes all data from the Pets
table and then issues a ROLLBACK
statement to undo that deletion. You can protect yourself by following this pattern. Wrap critical DELETE
and UPDATE
statements in a transaction. Then, you can roll back in the event you mistype, omit the WHERE
clause, or otherwise make a mistake.
Isolating Transactions
When you issue a BEGIN TRANSACTION
statement, you are telling SQL Server that from this point in the T-SQL
batch, you intend to isolate the effect of the statements from the rest
of the user connections. Each transaction lasts either until it
completes without errors and a COMMIT TRANSACTION
statement is issued or until errors are encountered and all modifications are erased with a ROLLBACK TRANSACTION
statement.
To help illustrate the transactional isolation
from the rest of user connections, consider the following case where
there are two different connections to SQL Server. User1
is connected and issues the following statement:
BEGIN TRANSACTION
UPDATE Pets SET pet_name='Big Boy' WHERE pet_id=5
SELECT pet_name FROM Pets WHERE pet_id=5
At this point, the result set for the SELECT
statement is as follows:
pet_name
Big Boy
User2
is connected to the same SQL Server and issues the following statement:
SELECT pet_name FROM Pets WHERE pet_id=5
The result set for User2
’s SELECT
statement follows:
pet_name
Rover
User2
still sees the old value until User1
issues a COMMIT TRANSACTION
statement.
This isolation is valuable and critical to
maintain consistency of the database. As a user, you can change the
behavior of the isolation. If User2
wanted to know the value even though User1
did not commit the transaction yet, User2
could manually set the transaction isolation level using the SET TRANSACTION ISOLATION
statement.
To read the uncommitted data in the Pets
table, User2
would issue the following code:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
SELECT pet_name FROM Pets WHERE pet_id=5
GO
This would return the uncommitted Big Boy
value instead of the original Rover
value. It is important to note that it is not a best practice to keep
transactions open; they take up valuable server resources, and other
users could be depending on the data being used within the transaction.
In this example, User1
should commit or roll back the transaction as soon as possible.
Deadlocks
Any time you have multiple users trying to
access and update the same piece of data, you will run into problems.
One user may have read a value and, based on that value, performed some
work, when in reality the value was updated right after the original
read and now causes problems for the user. SQL Server places locks at
different database levels, such as at rows or the entire table itself.
This makes the multiuser scenario possible.
A lock is a way to synchronize multiple
user access to the same piece of data. Locks have different modes, such
as shared or exclusive. Depending on the lock type and the actions each
user is trying to perform, you may end up in a deadlock situation. Deadlocks occur when User1
holds a lock on a resource and is requesting access to another resource that User2
holds a lock on. User1
has to wait for User2
to release the lock. However, User2
is also requesting a lock on User1
’s resource. Thus, User1
and User2
are both
waiting for each other to release the locks. In the end, SQL Server
will choose one to be the victim and roll back that user’s transaction.
SQL Server does a good job of providing tools
to debug deadlock situations. You can use SQL Server Profiler to
capture a SQL trace. Figure 1 shows the output of SQL Server Profiler when a deadlock was encountered.
Figure 1. SQL Server Profiler trace showing a deadlock event
For a deadlock event, SQL Server Profiler
displays the server process IDs that were involved with the deadlock,
as well as the deadlock victim. Figure 2 shows a detailed view of the deadlock graph showing the actual T-SQL statement that was issued by the deadlock victim.
Figure 2. Deadlock event showing T-SQL statement issued by the deadlock victim