2017-05-29 1 views
0

Dans mon cas, je souhaite créer plusieurs tags en appelant la méthode "createTags()". Pour tester la commodité, je viens d'utiliser @GET et pas de paramètres dans cette méthode, s'il vous plaît ne me dérange pas. Et je veux que toutes les opérations soient annulées si l'une d'elles lance une exception, par ex. Si tagValue de t3 est vide, t1, t2 ne devrait pas exister dans ma base de données. Évidemment, je devrais utiliser @Transactional ici, donc ma question est que puis-je utiliser @Transactional de cette façon? Je veux l'utiliser dans ma couche REST. Voici le code:@Transactional dans la couche REST ou dans la couche Service? Ce qui est mieux?

TestREST.class

@Path("tag/create") 
@GET 
@Transactional(rollbackOn = {NoTagException.class, TagAlreadyExistedException.class})) 
public void createTags() throws NoTagException, TagAlreadyExistedException { 
    // create all categories 
    Tag t1 = new Tag(TagType.CATEGORY); 
    t1.setTagValue("Edu"); 
    tagService.createTag(t1); 
    Tag t2 = new Tag(TagType.CATEGORY); 
    t2.setTagValue("ZJNU"); 
    tagService.createTag(t2); 
    Tag t3 = new Tag(TagType.CATEGORY); 
    // the value is empty here so I hope all previous operations rollback 
    t3.setTagValue(""); 
    tagService.createTag(t3); 
} 

TagService.class

public void createTag(Tag tag) throws NoTagException, TagAlreadyExistedException { 
    if (tag.getType() == null || !(tag.getType() instanceof TagType)) { 
     throw new NoTagException("tag's type must be set"); 
    } else if (tag.getTagValue() == null || tag.getTagValue().equals("")) { 
     throw new NoTagException("tag's value must be set!"); 
    } else { 
     Optional<Tag> existedTag = retrieveTagByTypeAndValue(tag.getType(), tag.getTagValue()); 
     if (existedTag.isPresent()) { 
      throw new TagAlreadyExistedException("one or more tags are already existed!"); 
     } else { 
      tagDAO.create(tag); 
     } 
    } 
} 

Ou devrais-je utiliser toujours @Transactional dans ma couche de service? Je change les méthodes ci-dessus à ceci:

TestREST.class

@Path("tag/create") 
@GET 
public void createTags() throws NoTagException, TagAlreadyExistedException { 
    // create all categories 
    Set<Tag> tags = new HashSet<>(); 
    Tag t1 = new Tag(TagType.CATEGORY); 
    t1.setTagValue("Edu"); 
    Tag t2 = new Tag(TagType.CATEGORY); 
    t2.setTagValue("ZJNU"); 
    Tag t3 = new Tag(TagType.CATEGORY); 
    t3.setTagValue(""); 
    tags.add(t1); 
    tags.add(t2); 
    tags.add(t3); 
    tagService.createTags(tags); 
} 

TagService.class

@Transactional(rollbackOn = {NoTagException.class, TagAlreadyExistedException.class})) 
public void createTag(Tag tag) throws NoTagException, TagAlreadyExistedException { 
    // just the same as above 
} 

public void createTags(Set<Tag> tags) throws NoTagException, TagAlreadyExistedException { 
    if (tags.isEmpty()) { 
     throw new NoTagException("tag must be set"); 
    } else { 
     for (Tag tag : tags) { 
      createTag(tag); 
     } 
    } 
} 

Ils peuvent tous atteindre ce que je pensais. Alors, quelle approche devrais-je choisir? Pourquoi? Et des suggestions que je peux améliorer ces méthodes? BTW, j'utilise CDI @RequestScoped dans TestREST.class et TagService.class Merci pour votre aide!

+0

Je ne pense pas que vous devriez vous imposer une règle de toujours mettre '@ Transactional' sur la même couche. Je pense que vous devriez le mettre dans l'endroit qui rend votre transaction aussi petite que possible, tout en gardant vos données cohérentes. – marstran

+0

@marstran Peut-être comme une nouvelle abeille, je suis trop exagéré. Lol, merci ~~ – MarcuX

Répondre

3

Je pense que cette question est moins sur l'utilisation de Transactional, et plus sur la façon dont le code est structuré.

Dans cet exemple, l'ajout de @Transactional au calque de repos permettra d'atteindre le but exact que vous souhaitez (enregistrer toutes les balises ou aucune en fonction de l'erreur). La question devient: «où la logique métier devrait-elle exister? Si le point de terminaison n'est qu'une méthode de collecte de données et qu'une méthode de service prend les données et tente de les enregistrer, l'annotation transactionnelle doit exister à ce niveau.

Il y a deux concepts que j'ai trouvé des gens beaucoup plus intelligents que moi en utilisant régulièrement. Déplacez l'annotation Transactional vers le calque le plus fin qui a du sens; et, annoter les méthodes d'interface sur des méthodes concrètes. Ce dernier ne s'applique pas ici, en soi (mais j'espère que cela vous aidera à l'avenir), mais le premier devrait être votre guide.

Pour réitérer, la question est moins sur où @Transactional devrait être placé .. Il devrait être, "où sera l'appel pour enregistrer les étiquettes être effectué"; et le @Transactional suivra.

(Hope this helps)

+0

_La question devient, "où la logique métier doit-elle exister?", Mon code de logique métier est toujours dans ma couche de service ~~ – MarcuX

+0

Quoi qu'il en soit, je pense obtenir ce que je veux dans le paragraphe 3 et 4 de votre réponse, merci beaucoup de donner des suggestions au-delà de cette question elle-même! – MarcuX

1

Habituellement, vous souhaitez trouver l'annotation @Transactional dans le Service Layer parce que c'est la couche qui connaît les autres unités de travail et c'est généralement la couche que vous gérez les exceptions, par ex. RuntimeException.

+0

Merci, et Lol ... Je pense que j'ai une autre question, comment gérer efficacement les exceptions dans ma couche de service? Pourriez-vous s'il vous plaît me montrer des URL utiles auxquelles je peux me référer? Peut-être que je devrais ouvrir une nouvelle question ~~ – MarcuX

+0

Le web, et en particulier le forum SO contient toutes les informations que vous aimeriez connaître sur 'Exceptions handling'.Dans le cas où vous avez une question spécifique (comme celle avec laquelle vous avez ouvert ce fil) n'hésitez pas à demander et je vais vous donner ma meilleure réponse. –

+0

Cool, merci agagin! – MarcuX

1

Lorsque la transaction la conception d'une application ci-dessous l'un des modèle de conception de transaction peut être utilisé en fonction de l'architecture/type d'une application

client Propriétaire Transaction Design Motif service Propriétaire du Domaine Transaction Modèle de conception Motif de conception de transaction de propriétaire délégué de délégué

Pour la plupart des applications d'entreprise Java Le modèle de conception de transaction de propriétaire de service de domaine est utilisé dans lequel le composant Domaine d'une application gère les transactions. ion

Lorsque nous voulons déplacer la responsabilité de la transaction à la couche de présentation Design Pattern de transaction du propriétaire du client est utilisé

Sever Délégué Propriétaire Transaction Pattern Design est utilisé lorsque l'on veut tirer parti de modèle de commande dans une application

du propriétaire du client est utilisé lorsqu'une application n'a pas de service agrégé et que plusieurs appels client à distance sont nécessaires pour exécuter une action métier. Dans votre code, vous appelez le même service plusieurs fois pour créer des balises dans la couche REST. Il n'y a donc aucune raison de placer la responsabilité de la transaction dans la couche de présentation. Pour les besoins de votre entreprise, il est préférable de transférer la responsabilité des transactions sur la couche intermédiaire à l'aide du modèle de propriétaire de service de domaine En outre, l'utilisation du modèle de propriétaire client impose trop de responsabilités d'infrastructure côté client, ce qui augmente le chat. Couche de présentation devrait seulement responsable de la présentation des données, mais la couche de présentation de la force du propriétaire du client Patter pour maintenir la responsabilité côté serveur aussi il n'est pas bon. Le propriétaire du service de domaine est couramment utilisé pour la plupart des entreprises Java basées sur une application. Dans ce modèle, le composant de domaine de votre application, c'est-à-dire l'article, la commande, l'inventaire et, dans votre cas, le tag est responsable de la transaction. Donc, pour les exigences métier, ce modèle doit être utilisé

Le modèle de conception de transaction de propriétaire de délégué de serveur est utilisé lors de l'utilisation de modèle de commande dans l'application et il résout le problème concernant le modèle du propriétaire du client. En commande La fonctionnalité Motif est placée dans Commande et envoyée au serveur pour exécution. Le composant Command Processor du côté serveur gère la transaction.

Une règle simple pour gérer une exception efficacement dans une transaction est la couche/composant qui gère la transaction doit gérer l'exception et faire des opérations commerciales pour cette exception. La gestion de la transaction inclut le début de la transaction, la transaction de transaction et la transaction rollback afin que ces trois opérations soient placées dans le composant qui possède la responsabilité de transaction

Je suggère de passer par la version pdf Stratégies de conception de transactions Java que j'ai téléchargées dans la mienne ci-dessous Git Repo pour apprendre en profondeur sur le modèle de conception de transaction.

https://github.com/anurag1986/Transaction-Material

+0

Wow, merci pour votre réponse, c'est très spécifique. – MarcuX