I'd definitely also go Friso's way of moving the loop back into the database by writing a single SQL statement. However, from your description, that might not be so easy, as there are also deletions involved, and MySQL doesn't support the MERGE statement, which seems to be the perfect fit for this.
Currently, jOOQ doesn't have any convenience API to run dynamic multi-row inserts easily the way you intended. The relevant feature request is here:
You can, however, easily map-reduce your collection into an insert statement as follows:
permissions
.stream()
.collect(Collector.of(
() -> DSL.using(transaction)
.insertInto(USER_PERMISSION_TABLE)
.columns(USER_PERMISSION_TABLE.USER_ID, USER_PERMISSION_TABLE.PERMISSION_ID),
(q, p) -> q.values(user.getId(), p),
(q1, q2) -> null, // No parallel streams supported
))
.execute();