Found it, sort of. The SELECT FOR UPDATE was being caused by he DB (Postgres). It uses a SELECT for UPDATE on Referential Integrity (RI) links. The has the side effect of an insert on (say) a transaction table to lock all related tables. The side effect of that is a SEVERE drop in throughput (only one at a time).
Solution? Upgrade to Postgres 8.1. It handles locking for RI differeht by introducing a UPDATE FOR SHARE which uses a shared lock rather than an exclusive one.
As for deadlocking - still it is REPEATABLE_READ that is the culprit. I'd recommend that the default is change away from this to READ_COMMITTED. Much safer.