How can I lock rows FOR UPDATE without returning data over the connection?
About the goal to avoid deadlocks: see my answer to your related question:


Why am I getting a deadlock for a single UPDATE query?


About the question in the title:

You can use an empty SELECT list with a locking clause:

SELECT FROM foos WHERE owner_id = 123 AND unread ORDER BY id FOR UPDATE;


Still locks all selected rows, but does not return any data. Still returns empty rows, though, so you still get a row count like usual.

Or, inspired by a_horse's comment:

SELECT count(*) AS locked_rows
FROM  (SELECT FROM foos WHERE owner_id = 123 AND unread ORDER BY id FOR UPDATE) sub;


This way you get a single result row with the number of locked rows. (You can abort in case of 0 rows.) Rows are locked all the same. The SELECT list in the subquery can still be just empty (shortest, cheapest).

Aside: and unread=true is just a noisy, less efficient way of saying AND unread.

If unlocked can be NULL, consider to use unread IS NOT true in both statements.