Tracing, debugging and fixing Row Lock Contentions Off late, I've been facing a lot of row lock contentions. The table in contention seems to be a particular table. 

This is generally what happens - 


Developer 1 starts a transaction from Oracle Forms front end screen
Developer 2 starts another transaction, from a different session using the same screen


~5 minutes in, the front end seems unresponsive. Checking sessions shows row lock contention. The "solution" that everyone throws around is to kill sessions :/

As a database developer 


What can be done to eliminate row lock contentions?
Would it be possible to find out which line of a stored procedure is causing these row lock contentions
What would be the general guideline to reduce/avoid/eliminate such problems which coding?


If this question feels too open-ended/insufficient information please feel free to edit/let me know - I'll do my best to add in some additional information.



The table in question is under a lot of inserts and updates, I'd say it's one of the most busiest tables. The SP is fairly complex - to simplify - it fetches data from various tables, populates it into  work tables, a lot of arithmetic operations occur on the work table and the result of the work table is inserted/updated into the table in question.



The database version is Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit. The flow of logic is executed the same order in both the sessions, the transaction isn't kept open for too long ( or at least I think so), and the locks occur during active execution of transactions.



Update: The table row count is larger than I expected, at about 3.1 million rows. Also, after tracing a session I found that couple of update statements to this table are not utilizing the index. Why is it so - I'm not sure. The column referenced in the where clause  is indexed. I'm currently rebuilding the index.
Would it be possible to find out which
  line of a stored procedure is causing
  these row lock contentions?


Not exactly but you can get the SQL statement causing the lock and in turn identify the related lines in the procedure.

SELECT sid, sql_text
FROM v$session s
LEFT JOIN v$sql q ON q.sql_id=s.sql_id
WHERE state = 'WAITING' AND wait_class != 'Idle'
AND event = 'enq: TX - row lock contention';



  What would be the general guideline to
  reduce/avoid/eliminate such problems
  with coding?


The Oracle Concepts Guide section on locks says, "A row is locked only when modified by a writer."  Another session updating the same row will then wait for the first session to COMMIT or ROLLBACK before it can continue.  To eliminate the problem you could serialize the users, but here are some things that can reduce the problem perhaps to the level of it not being an issue.


COMMIT more frequently.  Every COMMIT releases locks, so if you can do the updates in batches the likelihood of another session needing the same row is reduced.
Make sure you aren't updating any rows without changing their values.  For example, UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1); should be rewritten as the more selective (read fewer locks) UPDATE t1 SET f1=f1+1 WHERE f2=’a’;.  Of course if the changing the statement will still lock the majority of rows in the table then the change will only have a readability benefit.
Make sure you are using sequences rather than locking a table to add one to the highest current value.
Make sure you aren’t using a function that is causing an index to not be used.  If the function is necessary consider making it a function based index.
Think in sets.  Consider whether a loop running a block of PL/SQL doing updates could be rewritten as a single update statement.  If not then perhaps bulk processing could be used with BULK COLLECT ... FORALL.
Reduce the work that gets done between the first UPDATE and the COMMIT.  For example, if the code sends an email after each update, consider queuing the emails and sending them after committing the updates.
Design the application to handle waiting by doing a SELECT ... FOR UPDATE NOWAIT or WAIT 2.  You can then catch the inability to lock the row and inform the user that another session is modifying the same data.