Business Central AL Transactions: COMMIT, Locks & Deadlocks
Transaction handling is one of the most important topics for an experienced Business Central developer. A procedure can produce the correct result in a small test environment and still create blocking, inconsistent intermediate states or deadlocks when many users and background processes execute it at the same time.
1. What is a transaction in Business Central?
A transaction is a unit of database work. During AL execution, when a write operation requires a transaction, the runtime automatically starts one. When execution completes, the transaction is normally ended and the updates are committed.
Microsoft documents that Database.Commit() ends the current write transaction. If code needs multiple write transactions during one execution, an explicit Commit() separates those transaction boundaries.
Microsoft Learn — Database.Commit() Method
2. Automatic transaction behavior
Consider a simple operation:
Customer.Get('10000');
Customer."Credit Limit (LCY)" := 50000;
Customer.Modify();
You normally do not need to call Commit() just to save this change. The AL runtime manages the transaction created by the write operation.
3. What does COMMIT actually do?
Database.Commit() ends the current write transaction. This is important because everything written before the commit belongs to the transaction that is being ended, while subsequent writes can belong to another transaction.
InsertRecordA();
Database.Commit();
InsertRecordB();
This creates two transaction phases. The first phase is committed before the second begins.
4. Why unnecessary COMMIT can be dangerous
A common mistake is adding Commit() whenever a developer wants to “make sure the record is saved.” This can change the atomicity of the process.
Imagine an operation that creates a header, creates lines and finally posts a document. If you commit halfway through and a later step fails, the earlier changes may already be permanent. Without that intermediate commit, the whole operation can remain within one transaction boundary and fail as one unit.
CreateHeader();
CreateLines();
// Avoid an unnecessary COMMIT here
PostDocument();
The correct boundary depends on the business requirement. The question is not “Where can I put COMMIT?” but “Which changes must be permanently committed before the next independent phase starts?”
5. COMMIT and long-running processes
There are cases where a large process intentionally uses smaller transaction units. For example, a background process may process thousands of independent records. Keeping every update in one enormous transaction can increase the amount of work and locks held together.
if Item.FindSet() then
repeat
ProcessItem(Item);
Database.Commit();
until Item.Next() = 0;
However, this pattern changes failure semantics: records processed before a commit can remain committed even if a later record fails. It should therefore be used only when each unit can safely succeed independently.
6. Database locks in AL
When AL updates data, the database may take locks so concurrent processes do not modify the same data in conflicting ways. Microsoft notes that locking can become a performance issue when processes wait for other processes to release resources.
The practical goal is to keep the time and scope of locks as small as the business process allows.
Microsoft Learn — Performance articles for developers
7. Record.LockTable()
Record.LockTable() explicitly requests update locking for subsequent reads against the table of the record variable until the transaction is committed. This should be used deliberately, not as a general-purpose performance fix.
Item.LockTable();
if Item.Get('1000') then begin
Item.Inventory := Item.Inventory + 10;
Item.Modify();
end;
Microsoft recommends delaying explicit locking as much as practical so that only data actually within the update scope is locked.
Microsoft Learn — Reducing database locking
8. How to reduce lock duration
- Read setup and configuration information before starting a write-heavy phase.
- Perform validation before acquiring locks where possible.
- Keep business logic inside the transaction focused.
- Avoid slow external HTTP calls while holding database locks.
- Do not hold a lock while waiting for user interaction.
- Use appropriate keys and filters so database operations are efficient.
- Split independent large workloads into safe transaction units when the business process permits it.
Microsoft's performance guidance specifically recommends limiting the time locks are held and limiting transaction size where appropriate.
9. The integration trap: database transaction + HTTP call
One of the most important architectural considerations is avoiding long database transactions around external calls.
Begin write transaction
↓
Modify Business Central data
↓
Call external API ← network delay
↓
Wait for response
↓
Modify more data
↓
Commit
An external API can be slow, unavailable or rate-limited. Holding database resources while waiting for an external system can increase contention.
A safer architecture often separates preparation, external communication and final database updates. The exact pattern depends on whether the operation requires strict atomicity.
10. What is a deadlock?
A deadlock occurs when two or more transactions block each other because each transaction holds a resource that another transaction needs. SQL Server can resolve a deadlock by terminating one of the transactions and rolling it back.
For example:
Transaction A Transaction B
------------ ------------
Locks Customer Locks Sales Header
Needs Sales Header Needs Customer
│ │
└──────── waiting ─────────────┘
↓
DEADLOCK
Microsoft provides deadlock monitoring and telemetry to help identify the AL object, method and database resources involved.
Microsoft Learn — Monitoring SQL Database Deadlocks
11. How to design to reduce deadlocks
Use a consistent access order
If two processes need the same tables, accessing them in a consistent logical order can reduce circular waiting.
Keep transactions short
The longer a transaction holds resources, the greater the opportunity for another process to collide with it.
Avoid unnecessary LockTable calls
Explicit locking should correspond to a real concurrency requirement. It should not be added simply because a process occasionally experiences a performance problem.
Do not mix unrelated work in one transaction
Unrelated calculations, external calls and large loops can unnecessarily increase the lifetime of the transaction.
12. Error handling and transactions
Error handling must be designed together with transaction behavior. A developer should understand which changes are still part of the current transaction and which changes have already been committed.
Try methods are another special case. Microsoft documents that database changes made by a try method aren't rolled back. For Business Central on-premises, database write transactions inside try methods are restricted by default and can produce a runtime error unless the server configuration allows them.
Microsoft Learn — Handling errors using try methods
13. A practical transaction design pattern
Validate input
↓
Read setup / configuration
↓
Prepare data
↓
Start focused write phase
↓
Update related records
↓
Finish transaction
↓
Run independent next phase
This structure makes transaction boundaries easier to reason about. Validation and read-only preparation can often happen before the critical write section, while the write phase can remain as small and deterministic as practical.
14. Troubleshooting locks and deadlocks
When users report that a page is slow or an operation occasionally fails, do not immediately add COMMIT or LockTable. First determine what is actually happening.
- Identify the AL operation and object involved.
- Check whether multiple sessions are processing the same records.
- Review database lock information when available.
- Use the Performance Profiler and debugging tools to find slow operations.
- Inspect telemetry for long-running queries and deadlock information.
- Look for external calls or unnecessary work inside write transactions.
Business Central's troubleshooting guidance includes tools for investigating performance issues, database locks, events, permissions and AL debugging.
Microsoft Learn — Troubleshooting tools and guides overview
15. Interview questions you should be ready for
- What is a transaction in Business Central? Explain the unit of database work and the runtime-managed default behavior.
- Why do we use Database.Commit()? To explicitly end the current write transaction and create a new transaction boundary for subsequent writes.
- Why should COMMIT not be used everywhere? It can break the intended atomicity of a business operation.
- What is Record.LockTable()? It requests update locking for subsequent reads against the table involved until the transaction is committed.
- What is a deadlock? Two or more transactions wait on resources held by each other, creating circular blocking.
- How do you reduce deadlocks? Keep transactions short, reduce unnecessary locks, use consistent access patterns and investigate the actual contention.
- Should an HTTP call happen inside a write transaction? Avoid it when possible because network latency can unnecessarily extend the transaction and lock lifetime.
- Does a TryFunction automatically roll back database changes? No. Microsoft explicitly documents that changes made by a try method aren't rolled back.
16. Practical checklist for production AL code
- Do I really need an explicit
Commit()? - What must be atomic in this business process?
- Can validation happen before the write phase?
- Am I holding locks while doing slow work?
- Could an external API call be moved outside the critical transaction?
- Can two background jobs touch the same records concurrently?
- Is the transaction too large for the workload?
- Have I considered failure behavior after every explicit commit?
- Can the problem be measured with profiler or telemetry before changing the locking strategy?
Conclusion
Strong Business Central development requires more than knowing AL syntax. Understanding transactions, COMMIT, locks and deadlocks helps you build extensions that behave predictably under concurrent workloads.
The key is to make transaction boundaries intentional: preserve atomic business operations where required, keep locks short, avoid unnecessary explicit locking, and separate slow external work from critical database updates whenever the architecture permits it.