Lock contention is one of the most common — and most disruptive — issues in IBM i environments. It can freeze applications, delay batch jobs, and leave users staring at "record in use" messages with no clear explanation. Yet with the right knowledge, most lock problems are both diagnosable and preventable.
This guide covers how IBM i locking works, the five most common lock scenarios, a structured troubleshooting process, and proven prevention strategies drawn from 17 years of real-world IBM i experience.
IBM i uses a sophisticated locking mechanism to protect data integrity in multi-user environments. Understanding its fundamentals is essential before you can diagnose problems effectively.
IBM i locks are object-based — they can be placed on entire objects, not just records. They are hierarchical, meaning a file-level lock affects all record-level operations within that file. They are mostly automatic, managed by the system based on your operations, but configurable through parameters like WAITRCD and WAITFILE.
Multiple jobs can read simultaneously. No updates allowed while held. Common in SELECT queries without FOR UPDATE. Lowest level of restriction.
Multiple jobs can read and update different records. Most common in OLTP applications. Balances performance and data integrity.
Multiple jobs can read, but no updates allowed by anyone. Used for reporting and queries that must prevent data changes during the read.
Only one job can read. No other access allowed. Rarely used in practice due to its highly restrictive nature.
Only one job can access the object. Blocks all other access attempts. Used for file reorganization and backups. Most restrictive type.
Two or more jobs are waiting for each other to release locks, creating a circular dependency that can never resolve on its own.
WRKACTJOB /* Identify the deadlocked jobs */
ENDJOB JOB(jobname) OPTION(*IMMED) /* End one to break the cycle */
// Always lock Customer first, then Order — in every program
CHAIN (custNo) CUSTMAST;
CHAIN (ordNo) ORDMAST;
// Set appropriate timeouts — never wait forever
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
OVRDBF FILE(CUSTMAST) WAITRCD(30)
/* Fail after 30 seconds instead of waiting forever */
An interactive user locks a record, then abandons their session — for a meeting, lunch, or simply leaving for the day — leaving batch jobs waiting indefinitely.
WRKOBJLCK OBJ(MYLIB/CUSTMAST) OBJTYPE(*FILE)
/* Look for LOCK STATUS: *HELD — identify the job holding it */
WRKJOB JOB(jobname)
/* Option 4: Display job attributes */
/* Check "Interactive transactions" — if 0, job is inactive */
ENDJOB JOB(jobname) OPTION(*CNTRLD) /* End the inactive job gracefully */
// Read without holding a lock
CHAIN (custNo) CUSTMAST;
oldVersion = custVersion;
// User makes changes — no lock held during this time
// Update only if version is unchanged since the read
EXEC SQL UPDATE CUSTMAST
SET custName = :newName,
custVersion = custVersion + 1
WHERE custNo = :custNo
AND custVersion = :oldVersion;
IF SQLCODE = 100;
// Record was changed by someone else — handle the conflict
ENDIF;
SELECT OBJECT_NAME,
OBJECT_LIBRARY,
JOB_NAME,
LOCK_STATE,
TIMESTAMPDIFF(2, CHAR(CURRENT_TIMESTAMP - LOCK_REQUEST_TIME))
AS MINUTES_HELD
FROM QSYS2.OBJECT_LOCK_INFO
WHERE LOCK_STATE = 'HELD'
AND TIMESTAMPDIFF(2, CHAR(CURRENT_TIMESTAMP - LOCK_REQUEST_TIME)) > 5
ORDER BY MINUTES_HELD DESC;
A single file-level exclusive lock blocks all record-level operations on that file, causing dozens of jobs to queue up and the system to appear frozen.
ADDJOBSCDE JOB(RGZORDMAST)
CMD(RGZPFM FILE(MYLIB/ORDMAST))
FRQ(*WEEKLY)
SCDDAY(*SUN)
SCDTIME(020000)
/* Run at 2 AM Sunday when no users are active */
CREATE VIEW ORDMAST_RO AS
SELECT * FROM ORDMAST
FOR READ ONLY;
GRANT SELECT ON ORDMAST_RO TO PUBLIC;
/* All reports use this view — they never conflict with OLTP updates */
Overly restrictive locks held longer than necessary cause excessive contention and degrade system performance — even without a full deadlock.
EXEC SQL DECLARE C1 CURSOR FOR
SELECT * FROM CUSTMAST
FOR UPDATE; // Locks all records even though we're just reading
EXEC SQL DECLARE C1 CURSOR FOR
SELECT * FROM CUSTMAST
FOR READ ONLY; // No update locks held
// Process in chunks with regular commits — locks released every 100 records
FOR i = 1 TO totalRecords BY 100;
EXEC SQL BEGIN TRANSACTION;
// Process 100 records
EXEC SQL COMMIT;
ENDFOR;
Lock contention occurs sporadically with no obvious pattern — different users affected at random times, locks that release on their own after a few minutes, and nothing obvious in job logs.
CREATE VIEW LOCK_MONITOR AS
SELECT OBJECT_NAME,
OBJECT_LIBRARY,
OBJECT_TYPE,
JOB_NAME,
LOCK_STATE,
LOCK_SCOPE,
LOCK_REQUEST_TIME,
CURRENT_TIMESTAMP AS CAPTURE_TIME
FROM QSYS2.OBJECT_LOCK_INFO;
-- Query periodically to capture patterns
SELECT * FROM LOCK_MONITOR
WHERE LOCK_STATE = 'HELD'
ORDER BY LOCK_REQUEST_TIME;
When a lock problem occurs, follow this systematic approach rather than guessing.
What operation is failing? Which file is involved? One user or many? Consistent or intermittent? Run WRKACTJOB and look for jobs in MSGW status.
Run WRKOBJLCK OBJ(library/object) OBJTYPE(*FILE). Look for LOCK STATUS: *HELD (this job has the lock) and *WAIT (this job is waiting).
For each job holding a lock: WRKJOB JOB(jobname), then Option 12: Work with locks. Note how long it has been held and whether the job is active.
For each waiting job, identify what it is waiting for. Check if that object is locked by another job. Continue until you reach the root cause.
Is it a deadlock (circular wait)? An abandoned lock (inactive job holding a lock)? A legitimate long operation? Or a design issue (wrong lock type, locks held too long)?
For deadlocks: ENDJOB one of the jobs. For abandoned locks: ENDJOB the inactive job with *CNTRLD. For legitimate operations: communicate with users and wait or reschedule.
Re-run WRKOBJLCK to confirm locks are released. Check WRKACTJOB to verify affected jobs are proceeding normally.
Document the incident, root cause, and resolution. Implement preventive measures. Monitor for recurrence.
Instead of holding locks during user interaction (which can last minutes), use row versioning to detect conflicts at update time. No lock is held between the read and the write.
// Most OLTP applications
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
// Reporting and analytics — no locks needed
EXEC SQL SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
// Critical operations requiring full repeatability only
EXEC SQL SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
EXEC SQL BEGIN TRANSACTION;
// Read data
// User interaction ← lock held here for unknown duration
// Update data
EXEC SQL COMMIT;
// Read data
// User interaction ← no lock held during this time
EXEC SQL BEGIN TRANSACTION;
// Update data only
EXEC SQL COMMIT;
OVRDBF FILE(CUSTMAST) WAITRCD(30)
/* Application fails cleanly after 30 seconds instead of hanging */
SELECT OBJECT_NAME,
OBJECT_LIBRARY,
COUNT(*) AS lock_count,
AVG(LOCK_DURATION) AS avg_duration_ms,
MAX(LOCK_DURATION) AS max_duration_ms
FROM QSYS2.OBJECT_LOCK_INFO
WHERE LOCK_STATE = 'HELD'
GROUP BY OBJECT_NAME, OBJECT_LIBRARY
ORDER BY lock_count DESC;
Problem: Nightly batch jobs failing 3–4 times per week due to locks held by abandoned interactive sessions.
Solution: Automatic session timeouts, pre-batch cleanup procedures, team training on lock awareness.
Problem: Frequent "record in use" errors causing customer service delays and user frustration.
Solution: Switched from pessimistic to optimistic locking, implemented conflict resolution screens, added lock monitoring.
Problem: End-of-day reports causing system-wide slowdowns that disrupted warehouse operations.
Solution: Created read-only views for reports, implemented READ UNCOMMITTED isolation, built pre-aggregated summary tables.
Lock management is a critical skill for any IBM i professional. The platform's locking mechanisms are powerful tools — when you understand them, you can use them to your advantage rather than fight against them.
The core principles that prevent most lock problems:
Most lock problems have a pattern. Once you learn to recognize them, you will resolve them faster — and eventually prevent them from occurring at all.