I used to have this as one of the options (4th param) passed to PDO constructor:
$aOptions[PDO::MYSQL_ATTR_INIT_COMMAND] = \"SET NAMES utf8\";
PDO::exec() should be used for queries that do not return a resultset, such as a delete statement or 'set'. PDO::query() should be used when you expect a resultset to be returned. It returns a PDOStatement object to you that you can iterate over to get the individual rows. Note though that if you're using data from an untrusted source in your queries prepared statements would be the best way to go for either kind of query (but you probably knew that).
So, in your case PDO::exec() would be right. Are you sure though that passing the set names command to PDO::__construct() as the last value doesn't work? It works for me and I have PHP 5.3 on Windows. Could you post some more sample code of what you're doing?