2011-04-12 3 views
1


J'ai un service où enregistrer beaucoup de données à db. En utilisant MYSQL Je l'ai utilisé comme cetteGrails rollback opération db sur une erreur

Domain1.withTransaction {text-> 
      def domain1=//Create my domain object to save 
      if(!domain1.save()){ 
       domain1.errors.each { 
         println it 
       } 
       throw new RuntimeException('unable to save domain1') 
     } 
     Domain2.withTransaction {text-> 
      def domain2=//Create my domain object to save 
      if(!domain2.save()){ 
       domain2.errors.each { 
         println it 
       } 
       throw new RuntimeException('unable to save domain2') 
     } 

Mon problème s'il se produisit un problème pour sauver domain2 je dois faire reculer domain1 sauver aussi.
Je dois enlever domain1 de db.

Répondre

3

Au lieu d'utiliser le traitement des transactions programatic, l'artefact de service permet la manipulation automatique des transactions. Cela conduit généralement à un code plus propre et plus maintenable.

Vous pouvez également utiliser la failonerror: true lorsque vous enregistrez() pour forcer un RuntimeException à être jeté.

Exemple ci-dessous:

class SomeService { 

    static transactional = false 

    def serviceMethod() { 
     def domain1=//Create my domain object to save 
     def domain2=//Create my domain object to save 
     domain1.save(failOnError:true) 
     domain2.save(failOnError:true) 
    } 
} 

MISE À JOUR

Je revisitant ce sujet, après avoir lu une réponse à un autre sujet. Grails Integration Test Does NOT Rollback

Veuillez vérifier que votre dialecte est configuré comme InnoDB car les tables MyISAM ne sont pas transactionnelles. Ceci est configuré dans votre Config.groovy

dataSource { 
     dialect= org.hibernate.dialect.MySQLInnoDBDialect 
     ... 
} 
+0

ne fonctionne pas pour moi. Si 'domain2.save' cause une exception RuntimeException, je peux voir l'effet de domain1.save dans ma base de données. – Jithin

+0

Y at-il une configuration que je dois définir pour cela? – Jithin

+0

Pourriez-vous vérifier que le service se trouve dans/grails-app/services? De plus, l'injection de dépendances est la seule façon de faire fonctionner les transactions déclaratives. Vous n'obtiendrez pas de service transactionnel si vous utilisez le nouvel opérateur tel que new SomeService() –

1

Essayez de retirer la partie Domain2.withTransaction {texte->. Vous êtes déjà dans une transaction avec votre premier appel. Si vous ne travaillez plus à l'intérieur des supports, vous devriez rester dans la même transaction et domain1 doit être annulée si vous jetez et exception après vérification domain2.

0

Mettez cette Domain2.withTransaction fermeture à l'intérieur Domain1.withTransaction fermeture, de sorte que l'erreur dans la transaction Domaine2 sera rollback à la fois la transaction Domain1 et DOMAIN2
Vous aimez cette

Domain1.withTransaction { 
     //.... 
     Domain2.withTransaction { 
      //.... 
     } 
} 
+0

Je ne pense pas que MySQL prend en charge les transactions imbriquées. Mais peut-être que tout cela arrive avant de frapper la DB? –

+0

Je ne sais pas exactement .. En tout cas son travail pour moi. –

0

Si vous voulez juste une seule transaction qui est annulée lorsqu'une non gérée sans contrôle exception est levée, puis ne démarrez pas une transaction imbriquée. Les modifications du code necessaary sont présentés ci-dessous:

Domain1.withTransaction {text-> 
    def domain1=//Create my domain object to save 
    if (!domain1.save()) { 
    domain1.errors.each { 
     println it 
    } 
    throw new RuntimeException('unable to save domain1') 
    } 

    def domain2=//Create my domain object to save 
    if (!domain2.save()) { 
     domain2.errors.each { 
     println it 
     } 
    throw new RuntimeException('unable to save domain2') 
    } 
}