Embora você possa fazer isso através de straight_join, você também pode obter explicitamente os bloqueios nas linhas que deseja duplicando o select ...for update no que deseja obter primeiro.
CREATE TEMPORARY TABLE colorsToUpdate (
colorID BIGINT(20) NOT NULL,
modelID BIGINT(20) NOT NULL
);
insert into colorsToUpdate ( colorID, modelID)
SELECT id, model_id
FROM colors
where id in (101, 105, 106);
#This will try to acquire lock on models
select m.* from models m
join colorsToUpdate c
on c.modelID = m.id
for UPDATE;
#this will try to get locks on models, and colors.
select m.*, c.*
from colorsToUpdate u
left join models m
on u.modelID = m.id
join colors c
on u.colorID = c.ID
order by m.id asc, c.id asc
for update;
# do your data modification here.
drop table colorsToUpdate;
Como o bloqueio é feito em várias etapas, seria possível que as entradas nas 'cores' da tabela fossem modificadas entre quando você configura a tabela temporária e quando você termina de obter os bloqueios nas duas tabelas.
Isso pode ser bom para você (ou seja, se você quiser apenas modificar as entradas existentes, quando a transação começar), mas pode causar bugs sutis se não for o que você deseja.