A resposta correta seria usar a seguinte afirmação:
INSERT INTO table (colA, colB) VALUES (?,?) ON DUPLICATE KEY
UPDATE colB = VALUES(colB);
No entanto, o problema parece que o hibernate não recebeu um valor de incremento automático de volta, uma vez que a instrução de atualização foi executada.
Encontrei a seguinte postagem no blog (http://www.jroller.com/mmatthews/entry/ obtendo_hibernate_and_mysql_s ) e modificou a consulta para o seguinte:
INSERT INTO table (colA, colB) VALUES (?,?) ON DUPLICATE KEY
UPDATE colB = VALUES(colB), id = LAST_INSERT_ID(id);
que finalmente funciona.
Um problema insolúvel com esta abordagem é que a inserção de duas entidades que são iguais dentro da mesma transação não funciona. Mesmo que a segunda inserção causasse a atualização correta, o em terminaria com 2 instâncias de entidade representando a mesma linha do banco de dados - o que não é permitido.
Para resolver isso, basta garantir que você não insira 2 entidades que são renderizadas iguais devido às suas restrições. (Eu usei a mesma lógica para equals/hashcode que a restrição de chave única composta, então posso eliminar essas duplicatas ao realizar inserções em lote)