SQL Server · TCL · Transaction Lab

SQL TCL Scripting for Automation

Learn to protect multi-step industrial data changes with BEGIN TRANSACTION, COMMIT, ROLLBACK and savepoints—including isolation, error handling and SCADA retry design.

Transactions COMMIT ROLLBACK Isolation and recovery

Learning Overview

Level: SQL transaction basicsFormat: Blog + practical labExample: dbo.tblEventEstimated time: 180 minutes

Prerequisites / What You’ll Need

  • A disposable SQF_DB database
  • SSMS with two query windows for concurrency tests
  • The dbo.tblEvent and dbo.Equipment practice tables
  • Basic INSERT, UPDATE and DELETE knowledge
  • A backup before testing against any existing database
Core idea

A transaction is a unit of work. Either every required process-data change succeeds and commits, or the unit rolls back. Keep the unit small, deterministic and independent of operator waiting time or external network calls.

  • COMMIT accepts a valid unit; ROLLBACK undoes it.
  • Use SET XACT_ABORT ON and TRY/CATCH for reliable server-side error handling.
  • An inner COMMIT does not commit the outer transaction.
  • Design retries with an idempotency key because connection loss can hide a successful commit.

SQL TCL for SCADA and Industrial Automation

This guide covers SQL Server transactions, COMMIT and ROLLBACK, SAVE TRANSACTION, XACT_STATE and XACT_ABORT and a complete SCADA transaction lab.

1. What Is TCL?

TCL means Transaction Control Language. It controls the boundary and outcome of a transaction.

StatementPurposeAutomation example
BEGIN TRANSACTIONStart an explicit unit of workBegin event + state update
COMMIT TRANSACTIONAccept a valid unitMake both changes complete
ROLLBACK TRANSACTIONUndo to transaction start/savepointRemove partial event write
SAVE TRANSACTIONCreate a rollback pointUndo an optional correction only

SQL Server starts and ends transactions according to session settings and statements. Every application should know who owns the transaction: the server procedure, the client connection or a higher-level coordinator.

2. ACID Properties in Automation Data

PropertyMeaningIndustrial example
AtomicityAll or none of the unit succeedsEvent row and charge status move together
ConsistencyRules remain validForeign keys and checks hold after commit
IsolationConcurrent units have defined visibilityReports do not consume half-finished changes
DurabilityCommitted changes survive failure according to database guaranteesA confirmed event remains recorded after restart

A transaction cannot correct a bad process model. Constraints, keys, validation and idempotency still define what “consistent” means.

3. Autocommit, Implicit and Explicit Transactions

ModeBehaviorRecommendation
AutocommitEach standalone statement is one transactionGood for independent single statements
ImplicitCertain statements start a transaction; client must commit/rollbackUse only when client lifecycle is well controlled
ExplicitBEGIN TRANSACTION starts a named unitUse for related statements that must succeed together
SELECT @@OPTIONS AS [SessionOptions];
DBCC USEROPTIONS;

-- Explicitly control this setting for predictable scripts.
SET IMPLICIT_TRANSACTIONS OFF;
Connection pooling: an uncommitted transaction left on a reused connection can block other work. Always commit or roll back before returning a connection to the pool.

4. BEGIN TRANSACTION and COMMIT

BEGIN TRANSACTION;

UPDATE [dbo].[tblEvent]
SET [Temp_Act] = 949.250
WHERE [ID] = 1250;

IF @@ROWCOUNT <> 1
BEGIN
    ROLLBACK TRANSACTION;
    THROW 50020, 'Expected one event row.', 1;
END;

COMMIT TRANSACTION;

Start the transaction immediately before the first required statement. Validate while it is open, commit promptly and return a clear outcome to the caller.

5. ROLLBACK TRANSACTION

BEGIN TRANSACTION;

DELETE FROM [dbo].[tblEvent]
WHERE [ChargeNo] = 'CH-LAB-ROLLBACK';

SELECT @@ROWCOUNT AS [RowsDeletedInsideTransaction];

ROLLBACK TRANSACTION;

SELECT COUNT_BIG(*) AS [RowsAfterRollback]
FROM [dbo].[tblEvent]
WHERE [ChargeNo] = 'CH-LAB-ROLLBACK';

A full rollback undoes data changes and releases transaction resources. Changes to local variables and table variables are not undone, so do not treat their content as proof that a database change committed.

6. Define the Automation Unit of Work

Group statements only when the business rule requires them to succeed together. This example records a transition and closes the previous event.

DECLARE @PreviousEventID int = 1249;

BEGIN TRANSACTION;

INSERT INTO [dbo].[tblEvent]
    ([DT], [SQF_No], [ChargeNo], [Event_From], [Event_To], [Temp_Set], [Temp_Act], [Fan_Status])
VALUES
    (SYSUTCDATETIME(), 2, 'CH-2026-0050', 'Heating', 'Soaking', 950.000, 949.250, 1);

UPDATE [dbo].[tblEvent]
SET [Event_To] = 'Soaking'
WHERE [ID] = @PreviousEventID AND [SQF_No] = 2;

IF @@ROWCOUNT <> 1
BEGIN
    ROLLBACK TRANSACTION;
    THROW 50021, 'Previous event not found.', 1;
END;

COMMIT TRANSACTION;

Do not include unrelated report queries, file writes, email calls or operator confirmations inside this database transaction.

7. TRY/CATCH with SET XACT_ABORT ON

SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    INSERT INTO [dbo].[tblEvent]
        ([DT], [SQF_No], [ChargeNo], [Event_From], [Event_To])
    VALUES
        (SYSUTCDATETIME(), 2, 'CH-2026-0051', 'Load', 'Heating');

    UPDATE [dbo].[tblEvent]
    SET [Fan_Status] = 1
    WHERE [ID] = 1250;

    IF @@ROWCOUNT <> 1
        THROW 50022, 'Expected one target event.', 1;

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0
        ROLLBACK TRANSACTION;
    THROW;
END CATCH;

XACT_ABORT ON causes many runtime errors to terminate and roll back a transaction. TRY/CATCH ensures your code inspects transaction state, cleans up and preserves the original error with THROW.

8. XACT_STATE and @@TRANCOUNT

CheckValueMeaning
XACT_STATE()1Active and committable
XACT_STATE()0No active transaction
XACT_STATE()-1Active but uncommittable; full rollback required
@@TRANCOUNT0+Number of unmatched transaction begins for the session
SELECT
    XACT_STATE() AS [TransactionState],
    @@TRANCOUNT AS [TransactionCount];

Use XACT_STATE() to decide whether a transaction can commit. Use @@TRANCOUNT to understand ownership/nesting, not to prove durability.

9. SAVE TRANSACTION and Partial Rollback

A savepoint marks a location inside an active transaction.

BEGIN TRANSACTION;

INSERT INTO [dbo].[tblEvent]
    ([DT], [SQF_No], [ChargeNo], [Event_From], [Event_To])
VALUES
    (SYSUTCDATETIME(), 2, 'CH-SAVEPOINT', 'Load', 'Heating');

SAVE TRANSACTION [BeforeOptionalCorrection];

UPDATE [dbo].[tblEvent]
SET [Temp_Act] = 9999.000
WHERE [ChargeNo] = 'CH-SAVEPOINT';

-- Undo only the optional correction.
ROLLBACK TRANSACTION [BeforeOptionalCorrection];

-- The INSERT before the savepoint remains part of this transaction.
COMMIT TRANSACTION;
Limits: savepoint rollback is not supported in distributed transactions. If XACT_STATE() = -1, roll back the full transaction because writing the rollback-to-savepoint record is not allowed.

10. Nested Transaction Behavior

BEGIN TRANSACTION;       -- @@TRANCOUNT = 1
BEGIN TRANSACTION;       -- @@TRANCOUNT = 2

COMMIT TRANSACTION;      -- @@TRANCOUNT = 1; not yet finally committed
COMMIT TRANSACTION;      -- @@TRANCOUNT = 0; outer transaction completes

An inner COMMIT only decrements @@TRANCOUNT. A ROLLBACK TRANSACTION without a savepoint rolls back the entire outer transaction and sets the count to zero.

Procedure design: a stored procedure must not accidentally commit a transaction started by its caller. Either own the transaction clearly or use a transaction-count/savepoint pattern designed for composability.

11. Transaction Isolation Levels

Isolation controls which concurrent changes a transaction can observe and how reads interact with writes.

LevelDirty readsNon-repeatable readsPhantomsTypical note
READ UNCOMMITTEDPossiblePossiblePossibleCan display data that later rolls back
READ COMMITTEDPreventedPossiblePossibleCommon SQL Server default
REPEATABLE READPreventedPreventedPossibleHolds read locks longer
SNAPSHOTPreventedPreventedPreventedUses row versions; database option required
SERIALIZABLEPreventedPreventedPreventedStrongest locking isolation; lowest concurrency
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;
-- Required statements
COMMIT TRANSACTION;

Do not select an isolation level by name alone. Test correctness, blocking, version-store cost and throughput with the actual acquisition/report workload.

12. Row-Versioning Isolation

READ_COMMITTED_SNAPSHOT changes read-committed behavior to use row versions for many reads. SNAPSHOT gives a transaction-consistent view when enabled and requested.

DBA decision

Enabling row versioning is a database configuration change, not a query hint to add casually. Plan tempdb/version-store capacity, update-conflict handling, long readers and monitoring.

Avoid using NOLOCK as a universal “performance fix.” It permits dirty and inconsistent reads and does not solve every form of blocking.

13. Locks and Blocking

Writers acquire locks to protect changes. Another session may wait until the transaction commits or rolls back.

SELECT
    r.[session_id], r.[status], r.[command],
    r.[blocking_session_id], r.[wait_type], r.[wait_time],
    r.[transaction_id]
FROM sys.dm_exec_requests AS r
WHERE r.[session_id] <> @@SPID
  AND (r.[blocking_session_id] <> 0 OR r.[wait_type] IS NOT NULL);

Reading this DMV requires appropriate diagnostic permissions. Solve blocking by shortening transactions, indexing predicates and reducing unnecessary work—not by killing sessions blindly.

14. Deadlocks and Bounded Retry

A deadlock occurs when sessions wait in a cycle. SQL Server chooses a victim and rolls that transaction back.

  • Access tables and keys in a consistent order.
  • Keep transactions short.
  • Create indexes that avoid wide scans.
  • Capture and analyze the deadlock graph.
  • Retry the complete unit only for recognized transient errors.
  • Use a bounded retry count with delay/jitter.
  • Make the operation idempotent before retrying.
Do not retry blindly: constraint violations, invalid data and permission errors are not transient. Retrying them increases load without fixing the cause.

15. Why Long Transactions Hurt Runtime

CauseImpactBetter design
Waiting for operator confirmationLocks remain openCollect input before BEGIN
Calling PLC/API inside transactionDatabase waits on network/deviceSeparate external work; use message/outbox design
Updating millions of rows at onceLog growth and blockingMeasured deterministic batches
Unconsumed query resultsConnection/transaction cannot finish cleanlyConsume or close results before next step
Missing error cleanupOrphan transaction in pooled connectionRollback in catch/finally path

16. Transactions Inside Stored Procedures

A simple procedure that owns its unit can use this pattern:

CREATE OR ALTER PROCEDURE [dbo].[usp_RecordTwoEvents]
    @SQF_No int,
    @ChargeNo varchar(50)
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    BEGIN TRY
        BEGIN TRANSACTION;

        INSERT dbo.tblEvent (DT, SQF_No, ChargeNo, Event_From, Event_To)
        VALUES (SYSUTCDATETIME(), @SQF_No, @ChargeNo, 'Load', 'Heating');

        INSERT dbo.tblEvent (DT, SQF_No, ChargeNo, Event_From, Event_To)
        VALUES (DATEADD(MILLISECOND, 1, SYSUTCDATETIME()), @SQF_No, @ChargeNo, 'Heating', 'Soaking');

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
        THROW;
    END CATCH;
END;
GO

If callers may already own a transaction, use a reviewed composable pattern with the entry @@TRANCOUNT and a savepoint. Do not improvise nested commits.

17. Transactions from ODBC, ADO or Python

A client transaction belongs to one live connection. Every command in the unit must use that same connection and transaction object.

Open connection
Begin transaction on that connection
Try:
    Execute parameterized INSERT
    Execute parameterized UPDATE
    Validate returned ID and affected-row counts
    Commit
Catch:
    Roll back if transaction is active
    Record the original error
Finally:
    Close/dispose the transaction and connection

Do not place GO inside an application command. Do not open a second connection for one of the statements and assume it joins the first local transaction.

18. Connection Loss and Idempotency

The network can fail after SQL Server commits but before the client receives confirmation. Retrying a plain INSERT can create a duplicate.

-- Example source-generated event key protected by a UNIQUE constraint.
INSERT INTO [dbo].[tblEventInbox]
    ([SourceEventID], [ReceivedUtc], [Payload])
VALUES
    (@SourceEventID, SYSUTCDATETIME(), @Payload);

Generate a stable source event ID before the first attempt, enforce uniqueness and return the existing result when a retry presents the same key. The key must identify the same logical event, not a new attempt.

19. Local vs Distributed Transactions

A local transaction covers one SQL Server connection/resource manager. Accessing linked servers or multiple transactional resources can promote the unit to a distributed transaction that depends on additional infrastructure and has different failure modes.

  • Prefer one database-owned procedure when possible.
  • Avoid network calls inside the transaction.
  • Use an outbox/message pattern for reliable cross-system workflows.
  • Test coordinator outages and recovery if distributed transactions are unavoidable.
  • Remember: savepoint rollback is not supported in distributed transactions.

20. Verify Transaction Behavior

-- Verify no transaction remains open in the current session.
SELECT XACT_STATE() AS [XactState], @@TRANCOUNT AS [TranCount];

-- Verify the logical unit.
SELECT [ID], [DT], [SQF_No], [ChargeNo], [Event_From], [Event_To]
FROM [dbo].[tblEvent]
WHERE [ChargeNo] = @ChargeNo
ORDER BY [DT], [ID];

-- During a controlled test, inspect the oldest active transaction.
DBCC OPENTRAN (N'SQF_DB');
Expected after completion: XACT_STATE() = 0 and @@TRANCOUNT = 0 on the connection.

21. Common TCL Errors and Fixes

SymptomLikely causeCheck or fix
Transaction count mismatchProcedure changed caller-owned transaction countDefine ownership and use a composable savepoint pattern
Cannot commit; transaction uncommittableXACT_STATE() = -1Full rollback, then rethrow original error
Locks persist after screen actionOpen transaction waiting on UI/networkCollect inputs before transaction; ensure cleanup
Duplicate after timeoutCommit succeeded but response was lostUse a stable idempotency key
Deadlock victimConflicting lock orderAnalyze graph, index/order consistently, bounded retry
Rollback to savepoint failsDistributed or uncommittable transactionRoll back entire transaction
Inner COMMIT did not release locksOuter transaction still activeInspect @@TRANCOUNT; outer owner must finish
Unexpected dirty valuesREAD UNCOMMITTED/NOLOCKUse an isolation level matching correctness needs

22. Complete Practical TCL Lab

Hands-on
Lab safety
  • Use a disposable SQF_DB copy.
  • Open two SSMS windows for blocking tests.
  • Never leave either session with @@TRANCOUNT > 0.
1

Observe autocommit

Insert one lab event without an explicit transaction and confirm it is immediately visible from the second session.

2

Rehearse full rollback

BEGIN TRANSACTION;
INSERT dbo.tblEvent (DT, SQF_No, ChargeNo, Event_From, Event_To)
VALUES (SYSUTCDATETIME(), 2, 'CH-TCL-LAB', 'Load', 'Heating');
SELECT XACT_STATE() AS XactState, @@TRANCOUNT AS TranCount;
ROLLBACK TRANSACTION;
Expected: the inserted lab row is absent after rollback and transaction count returns to zero.
3

Commit a two-statement unit

Insert a new transition and update the previous event by ID. Require exactly one updated row, then commit.

4

Use a savepoint

Insert a valid event, save a point, perform an optional correction, roll back to the savepoint and commit the valid insert.

5

Observe blocking safely

In session A, update one lab row inside a transaction without committing. In session B, query/update the same key and observe waiting. Roll back session A immediately and confirm session B proceeds.

Expected: blocking ends as soon as session A commits or rolls back.
6

Test the error path

Run the TRY/CATCH template with a deliberately invalid foreign key in the test database. Confirm the complete unit rolls back, the original error is rethrown and no transaction remains open.

Lab complete

You can now define a transaction unit, commit or roll back correctly, inspect state/count, use savepoints, observe blocking and build a reliable error path.

TCL Deployment Checklist

  1. Define one business unit of work.
  2. Choose the transaction owner.
  3. Collect external inputs before BEGIN.
  4. Use parameterized DML and exact keys.
  5. Enable predictable error handling.
  6. Validate OUTPUT and row counts.
  7. Commit quickly or fully roll back.
  8. Verify no transaction remains open.
  9. Test blocking, deadlock, timeout and disconnect.
  10. Make retry-safe operations idempotent.

Further Reading

Frequently Asked Questions

What is TCL in SQL Server?

TCL controls transaction boundaries with BEGIN TRANSACTION, COMMIT, ROLLBACK and SAVE TRANSACTION.

What is the difference between COMMIT and ROLLBACK?

COMMIT accepts a valid unit, while ROLLBACK undoes changes to the transaction start or a savepoint.

What does XACT_STATE return?

It returns 1 for a committable transaction, 0 for no transaction and -1 for an uncommittable transaction.

Does an inner COMMIT make changes permanent?

No. It only decrements the transaction count; the outermost COMMIT completes the transaction.

How long should a SCADA transaction remain open?

As briefly as possible. Never wait for operator input, PLC tags or external network responses while holding it open.

Get the SQL Reporting and Automation Syllabus

Share your details and a Softwell advisor will contact you with practical SQL, SCADA and industrial reporting training options.

Build reliable SQL transactions for automation

Join practical online, classroom or corporate SQL Server, reporting and SCADA integration training.

Request Course Details
Verified learning pathway

Discuss SQL TCL and Automation Transaction Training

Explore practical SQL Server, PLC/SCADA integration and industrial data training options.

Content reviewed: 4 August 2026

☎ Call WhatsApp ✉ Email Enquire Now