Business Central v27: Locking & Blocking — Practical Guide + How to Use the Database Locks Page

If you’ve seen “The record is locked by another user” in a busy system, you know how painful blocking can be. This post explains locking vs. blocking in Dynamics 365 Business Central v27, what’s improved in recent versions to reduce contention, how to read and act on the Database Locks page, and the AL patterns I use to prevent most issues.

Locking vs. Blocking (quick refresher)

  • Locking is normal: BC (and SQL Server) protect data while a transaction changes it.

  • Blocking is the wait that happens when your session needs a lock that another session holds.

  • Deadlock is a circular wait; SQL cancels one transaction.

BC primarily locks rows; SQL can escalate to page or table locks if you touch many rows in one go. The shorter the transaction, the shorter the lock window.

What got better in v27 (and around it)

  • Tri-state locking (optimistic reads by default). Modern BC runs with tri-state locking so reads after writes can be performed more optimistically for higher concurrency (fewer “random” blocks). If you explicitly call LockTable, BC reverts to the older, stricter behavior for that table and disables those optimistic reads in that transaction.

  • Finer control from AL.

    • Record.ReadIsolation lets you request lock behavior per record variable (e.g., UpdLock only where needed), instead of flipping a global, pessimistic mode.

    • Database.CurrentTransactionType (or object TransactionType) sets read behavior before the transaction starts (e.g., Browse for big, read-only reports that shouldn’t block writers).

  • Parallel posting options. Recent releases added features so multiple users can post inventory/warehouse/jobs at the same time by allocating entry numbers differently to avoid locking ledger tables. If you run high volume, review and enable the relevant features.

  • Operational guardrails. Background-session limits and sensible timeouts help prevent a stuck job from holding locks forever. Telemetry signals for lock timeouts/deadlocks make diagnosis faster.


The Database Locks page — what it shows and how to use it

Open it: Tell Me (Alt+Q) → Database Locks. The page shows a snapshot of current locks: the table/resource, who holds the lock, who’s waiting, user/session info, and sometimes object details. It’s perfect for confirming “who is blocking what right now.”

What you’ll see: current locks (holder, waiters), resource type/mode/status, user, and AL object hints. It’s a point-in-time view—refresh to confirm if a lock is still active. For recurring issues, pair this page with telemetry to catch events even after the fact.

How to act (quick flow):

  1. Open Database Locks to identify the locking session and blocked sessions.

  2. Correlate in telemetry (lock timeout + lock snapshot) to tie the SQL session back to the AL session/object.

  3. Fix the source: shorten the transaction, adjust isolation only where needed, reschedule heavy jobs, or enable concurrency features.

Tip: The page gives visibility, not a kill switch. If you must stop a long-running task, use the Admin Center/telemetry tooling and then address the root cause.


Practical AL patterns (do this, not that)

1) Keep write transactions short (batch + commit)

Bad (one huge transaction):

if Item.FindSet() then repeat Process(Item); // updates many tables - long lock window until Item.Next() = 0;

Better (chunk work and release locks):

procedure UpdateItems() var Item: Record Item; n: Integer; begin if Item.FindSet(true) then // lock only rows we touch repeat // minimal per-row work Item."Last Reviewed Date" := Today; Item.Modify(); n += 1; if n mod 500 = 0 then Commit(); // free locks periodically until Item.Next() = 0; end;

2) Prefer surgical locks over global LockTable

Don’t:

Customer.LockTable(); Customer.Get(No); Customer.Modify(); // disables optimistic reads for this table in the tx

Do (targeted lock just where needed):

Customer.ReadIsolation := IsolationLevel::UpdLock; // only for this variable if Customer.Get(No) then Customer.Modify();

This keeps the tri-state benefits elsewhere in the transaction.

3) Make heavy reads non-blocking (reports, analytics)

For big read-only tasks where slightly stale data is acceptable:

trigger OnPreReport() begin Database.CurrentTransactionType := TransactionType::Browse; // non-locking reads end;

Set the transaction before the first DB call.

4) Remove serial bottlenecks (number series)

If volume contends on a single No. Series Line, consider Allow Gaps in Nos. for non-regulated documents to avoid the “single-file” queue on that record and improve throughput. (Use continuous numbering where regulation requires it.)

5) Plan maintenance to avoid escalation

Large deletes/inserts can escalate to page/table locks. Run them off-hours, chunk operations, or—when truly clearing a staging table—use Rec.Truncate() (where available) to finish fast and reduce lock duration.

6) Be careful with external calls inside transactions

Don’t hold DB locks while waiting on HTTP or long external work. Commit first or move the call outside the transactional scope.


References (official docs & deep dives)

Microsoft Learn — View Database Locks (how to open & use the page)

Microsoft Learn — Monitor Database Locks (developer/IT perspective)

Microsoft Learn — Page "Database Locks" (ID 9511)

Microsoft Learn — Table "Database Locks" (System.Diagnostics)

Microsoft Learn — Tri-state locking in database (optimistic reads)

Microsoft Learn — Performance gain by reducing locks (release plan context)

Microsoft Learn — Control database locking behavior (ReadIsolation intro)
https://learn.microsoft.com/en-us/dynamics365/release-plan/2023wave1/smb/dynamics365-business-central/control-database-locking-behavior

Microsoft Learn — Record.ReadIsolation method

Microsoft Learn — RecordRef.ReadIsolation method

Microsoft Learn — Database.CurrentTransactionType method

Microsoft Learn — TransactionType property (Browse/Snapshot/UpdateNoLocks/Update)

Microsoft Learn — Telemetry: Database lock timeout trace (RT0012) & lock snapshot

Microsoft Learn — Number Series (incl. Allow gaps where appropriate)

Microsoft Learn — Rec.Truncate (release plan; fast table clear)

Community — Waldo: Rec.LockTable – Good practice or bad practice?

Community — BC Internals: Tri-state locking deep dive

Community — Yun Zhu: Database Locks page overview

Comments

Popular posts from this blog

Understanding Database Indexes in Business Central (and How They Can Help You)