L'implémentation de la transaction Rails n'utilise pas les points d'arrêt (ou technologies similaires) utilisés par les bases de données pour prendre en charge les transactions imbriquées. Les vraies transactions imbriquées ne sont pas supoprted par les bases de données elles-mêmes.
exemple:
begin -- starts transaction 1
begin -- start transaction 2
insert into something (foo) values ('bar');
commit -- ends transaction 1
rollback -- is ignored
La première commit
ou rollback
ferme toujours le hors plus transaction.
Il existe un moyen par lequel les bases de données peuvent réellement effectuer l'imbrication. ceci utiliserait les points de sauvegarde précédemment mentionnés. exemple
begin -- starts transaction 1
savepoint foo -- starts "transaction" 2
insert into something (foo) values ('bar');
release -- commit for transaction 2
rollback -- roll back the data of the savepoint and everything else within transaction 1
Vous pouvez imbriquer autant savepoints que vous voulez dans l'autre, tant qu'une transaction est ouverte.
Pour les rails lui-même, il y a un problème: Les fonctions créent et se complètent dans une transaction. donc votre premier exemple produit le sql suivant
begin -- transaction.do
begin -- Client.create
insert into clients (name) values ('Pavel') -- Client.create
commit -- Client.create, closes the out-most transaction
begin -- transaction.do
begin -- Client.create
insert into clients (name) values ('Elena') -- Client.create
commit -- Client.create, closes the out-most transaction
Donc votre Exception arrive juste trop tard.
Vous pouvez corriger ce problème, mais vous devez le faire pour chaque adaptateur de connexion.
PS: Vous pourriez être dérouté par le --
dans le sql. Ce sont des commentaires d'une seule ligne dans MySQL ..
est ici une explication assez cool de ce comportement: http://stackoverflow.com/questions/22413599/why-does-rails-ignore-a-rollback- in-a-pseudonested-transaction – Ich