Quick answer: Retry the entire transaction after catching ORA-08177, or switch to READ COMMITTED isolation if you don't need strict consistency.
ORA-08177 shows up when you're running in SERIALIZABLE isolation mode and two transactions try to modify the same data at the same time. Oracle uses a snapshot of the database at the start of your transaction. When you try to update a row that another transaction has already changed and committed after your snapshot was taken, Oracle throws ORA-08177. It's not a data corruption issue—it's a conflict detection mechanism. The database is telling you, "Your view of the data is stale, so I won't let you overwrite someone else's work."
You'll often see this in apps that process financial transactions, like a banking system where two tellers update the same account balance, or in batch jobs that update overlapping ranges of rows. A common trigger: you run a report that updates a summary table while another session does the same thing.
Fix It in 5 Steps
- Identify which transactions are conflicting. Run this query to see active sessions and their SQL:
SELECT s.sid, s.serial#, s.status, q.sql_text
FROM v$session s, v$sql q
WHERE s.sql_id = q.sql_id
AND s.status = 'ACTIVE';
You'll see a list. Look for two sessions updating the same table. That's your culprit.
- Check your isolation level. In your application code, look for
SET TRANSACTION ISOLATION LEVEL SERIALIZABLEor a JDBC connection property likesetTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE). If you find it, that's why you're here. - Catch the error and retry. Wrap your transaction logic in a loop that catches ORA-08177 and re-runs the whole thing. Here's a PL/SQL example:
DECLARE
attempts NUMBER := 0;
BEGIN
LOOP
BEGIN
-- Your transaction here
UPDATE accounts SET balance = balance - 100 WHERE id = 42;
COMMIT;
EXIT; -- success
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -8177 AND attempts < 5 THEN
attempts := attempts + 1;
ROLLBACK;
ELSE
RAISE;
END IF;
END;
END LOOP;
END;
After you catch and rollback, the next attempt gets a fresh snapshot, so it won't conflict again—unless another session keeps stepping on you.
- If retries don't work, check for long-running transactions. Look at
v$transactionto see how long other sessions have been open:
SELECT t.sid, t.used_ublk, t.start_time
FROM v$transaction t;
If you see a session that's been running for hours, it's holding locks and causing your conflicts. You might need to contact that user and ask them to commit or rollback. In a development environment, you can kill the session with ALTER SYSTEM KILL SESSION 'sid,serial#'.
- If you can't change the app code, switch isolation at the session level. Run this before your transaction:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
But do this only if your business logic doesn't depend on seeing a consistent snapshot across multiple queries. You'll get fewer conflicts, but you might see data that changes mid-transaction.
Alternative Fixes If the Main One Fails
Sometimes retrying isn't enough because the conflict is frequent. Try these:
- Serialize the transactions at the application level. Use a lock table or a DBMS_LOCK to ensure only one process does the update sequence at a time. For example, call
DBMS_LOCK.REQUEST(12345, timeout => 60)before the transaction and release it after. - Use
SELECT FOR UPDATEto lock rows before updating. This forces other transactions to wait, but it can cause deadlocks if you're not careful. Lock rows in a consistent order. - Separate the conflicting operations. If two jobs update the same table, stagger their schedules or partition the data so each job touches different rows.
The real fix depends on your workload. For most apps, retrying is the standard pattern. But if you're seeing this error constantly, you've got a design issue—too many writers on the same data.
Prevention Tips
You can avoid ORA-08177 before it happens:
- Use
READ COMMITTEDfor most transactions. Oracle's default is the right choice for 95% of use cases. Serializable is only for specific reporting or analytics where you need a point-in-time view. - Keep transactions short. The longer a serializable transaction runs, the higher the chance someone else modifies the same data. Commit as soon as possible.
- Design your app to handle retries gracefully. Even with
READ COMMITTED, you might get deadlocks (ORA-00060), so a retry loop is good practice anyway. - If you must use serializable, ensure your queries are index-driven and touch the smallest set of rows possible. Full table scans increase the chance of conflicts because Oracle locks more rows in the snapshot.
I've seen teams waste days trying to tune around this error. The pragmatic answer is almost always: retry and move on. If that doesn't work, you're probably using the wrong isolation level for the job.