Utilisez-vous des tables InnoDB ou des tables MyISAM ? MySQL ne prend pas en charge les transactions sur les tables MyISAM (mais cela ne vous donnera pas d'erreur si vous essayez de les utiliser). Assurez-vous également que votre niveau d'isolation de transaction est défini de manière appropriée, il doit être SERIALIZABLE, ce qui n'est pas la valeur par défaut pour MySQL.
Cet article a un bon exemple qui explique l'impact des différents niveaux d'isolement en utilisant un exemple très similaire au vôtre.