2010-06-05 4 views
12

J'ai mis à jour tous mes services pour qu'ils soient transactionnels en utilisant la capacité de récupération de Grail lorsqu'une exception RuntimeException est lancée dans le service. Je, dans la plupart des cas, ce faisant:Annulation d'une transaction dans un service Grails

def domain = new Domain(field: field) 
if (!domain.save()) { 
    throw new RuntimeException() 
} 

Quoi qu'il en soit, je voulais vérifier que ce fait va annuler la transaction ... il m'a fait penser à si, à ce stade, il a déjà été commis .. De plus Si ce n'est pas le cas, cela mettrait de la couleur: vrai changement ça? Je ne suis pas très familier avec la façon dont Spring/Hibernate fait tout cela :)

Répondre

15

Oui, ça va le faire.

Les transactions dans Grails sont traitées par défaut à un niveau de méthode Service. Si la méthode revient normalement, la transaction sera validée. Si une exception RuntimeException est levée, la transaction sera annulée. Notez que cela signifie que même si vous utilisez flush: true lors de l'enregistrement d'un objet dans la méthode serveur, les changements de db seront toujours annulés si vous lancez une exception RuntimeException.

Par exemple:

class MyService { 

def fiddle(id,id2){ 
    def domain = Domain.findById(id) 

    domain.stuff = "A change" 
    domain.save(flush:true) // will cause hibernate to perform the update statements 

    def otherDomain = OtherDomain.findById(id2)  

    otherDomain.name = "Fiddled" 

    if(!otherDomain.save(flush:true)){ // will also write to the db 
    // the transaction will be roled back 
    throw new RuntimeException("Panic what the hell happened") 
    }               
} 
} 

Ce que je ne suis pas 100% clair avec Grails est ce qui se passe si une exception contrôlée est jeté dans le monde java droite/printemps le comportement par défaut est le Inceptor de transaction à la transaction, althrough cela peut être remplacé dans la config.

Remarque: il existe une mise en garde, à savoir que votre base de données doit prendre en charge les transactions sur les tables que vous mettez à jour. Oui, c'est poke chez MySQL :)

Cela s'applique également à la méthode Domain.withTransaction.

+0

Génial, merci! – RyanLynch

+0

content d'être de service –

+0

Les exceptions personnalisées qui étendent RuntimeException devraient être OK, n'est-ce pas? En outre, vous pouvez activer les transactions dans MySQL en réglant: dialect = org.hibernate.dialect.MySQLInnoDBDialect dans dataSource :) – RyanLynch

2

Je voulais juste ajouter des commentaires supplémentaires à la réponse acceptée, et c'était trop long pour entrer dans un commentaire.

Ce que je ne suis pas 100% clair avec Grails est ce qui se passe si une exception contrôlée est jeté

Par défaut, l'exception ne doit pas être vérifiée, ou la transaction ne sera pas roulé arrière. Apparemment, c'est une chose de printemps.

Si vous souhaitez vraiment vérifier les exceptions sur une méthode, vous pouvez marquer explicitement la méthode de service comme @Transactional et utiliser l'argument rollbackFor pour répertorier les exceptions qui doivent toujours provoquer une annulation. (Notez que je n'ai pas réellement testé ceci.)

Sachez cependant que le marquage d'une méthode dans un service avec @Transactional désactive l'encapsulation automatique de ses autres méthodes avec une transaction. Donc, si vous le faites pour un, vous devez le faire pour tous. Assurez-vous vraiment besoin de pour déclarer ces exceptions vérifiées;)

Vous pouvez en savoir plus à ce sujet à http://docs.grails.org/latest/guide/services.html.

Questions connexes