It's better to only do it in the stored procedure for a number of reasons:
- The procedure can keep better control of when to begin and commit the transaction.
- It can also control the isolation level, which should usually be set before the transaction starts.
- It keeps database code close to the database (somewhat subjective).
- If the connection is severed and the server does not realize, a transaction opened by the client may not be committed or rolled back for some time, and could leave locks hanging, causing a huge chain of blocking
- The client starting and committing the transaction requires two extra round-trips over the network, which in a low-latency app may be problematic. (
SET NOCOUNT ON
should be used for the same reason.) The transaction and associated locking is also extended for that time, casuing further blocking problems.
Do use SET XACT_ABORT ON
, in case of exceptions this will cause an automatic rollback and prevent them from leaving hanging transactions.
It may still may sense to use client-side transactions, especially with distributed transactions.
Having transactions in both client code and the procedure is silly and wasteful. Choose one or the other option and stick to it.