Quelle est la place de l'annotation @Transactional?

devriez-vous placer le @Transactional dans les classes DAO et/ou leurs méthodes ou est-il préférable d'annoter les classes de Service qui appellent en utilisant les objets DAO? Ou est-ce logique d'annoter les deux "couches"?

449
demandé sur Thomas Einwaller 2009-07-03 16:20:11

19 réponses

je pense que les transactions appartiennent à la couche Service. C'est celui qui connaît les unités de travail et les cas d'utilisation. C'est la bonne réponse si vous avez plusieurs DAOs injectés dans un Service qui ont besoin de travailler ensemble dans une seule transaction.

462
répondu duffymo 2009-07-03 12:23:49

en général, je suis d'accord avec les autres disant que les transactions sont généralement commencées au niveau du service (selon la granularité que vous exigez bien sûr).

cependant, entre-temps, j'ai aussi commencé à ajouter @Transactional(propagation = Propagation.MANDATORY) à ma couche D'OFA (et à d'autres couches qui ne sont pas autorisées à lancer des transactions mais qui en ont besoin) parce qu'il est beaucoup plus facile de détecter des erreurs où vous avez oublié de lancer une transaction dans l'appelant (par exemple le service). Si votre DAO est annoté avec la propagation obligatoire vous obtiendrez une exception indiquant qu'il n'y a pas de transaction active lorsque la méthode est invoquée.

j'ai aussi un test d'intégration où je vérifie tous les haricots (bean post processor) pour cette annotation et échoue s'il y a une annotation @Transactional avec propagation autre que obligatoire dans un haricot qui n'appartient pas à la couche services. De cette façon, je m'assure que nous ne démarrons pas les transactions sur la mauvaise couche.

268
répondu mnp 2011-08-30 06:50:33

les Annotations transactionnelles doivent être placées autour de toutes les opérations qui sont inséparables.

par exemple, votre appel est"change password". Qui consiste en deux opérations

  1. changer le mot de passe.
  2. Vérifier le changement.
  3. envoyer au client que le mot de passe a changé.

ainsi, si la vérification échoue, alors le mot de passe doit changer aussi l'échec? Si c'est le cas, la transaction devrait être d'environ 1 et 2 (donc à la couche service). Si l'e-mail échoue (probablement devrait avoir une sorte de sécurité d'échec sur ce afin qu'il n'échoue pas) alors devrait-il revenir le mot de passe de changement et l'audit?

ce sont le genre de questions que vous devez poser lorsque vous décidez où placer le @Transactional .

76
répondu Michael Wiles 2012-10-23 06:46:26

le cas normal serait d'annoter au niveau de la couche service, mais cela dépend vraiment de vos besoins.

annoter sur une couche de service entraînera des transactions plus longues que annoter au niveau de L'OFA. Selon le niveau d'isolement de la transaction qui peut vous poser des problèmes, comme les transactions concurrentes ne verront pas les changements de l'autre dans eg. LECTURE REPRODUCTIBLE.

annotant sur le DAOs gardera les transactions aussi courtes que possible, avec l'inconvénient que la fonctionnalité que votre couche de service expose ne sera pas fait dans une seule (rollbackable) transaction.

il n'est pas logique d'annoter les deux couches si le mode de propagation est défini par défaut.

37
répondu hammarback 2009-07-03 12:45:41

la bonne réponse pour les architectures à ressorts traditionnelles est de placer la sémantique transactionnelle sur les classes de service, pour les raisons que d'autres ont déjà décrites.

une tendance émergente au printemps est vers domaine-driven design (DDD). Spring Roo illustre parfaitement la tendance. L'idée est de rendre L'objet de domaine POJOs beaucoup plus riche qu'ils ne le sont sur des architectures de ressort typique (généralement ils sont anémique ), et en particulier pour mettre la sémantique des transactions et de la persistance sur les objets de domaine eux-mêmes. Dans les cas où tout ce qui est nécessaire est de simples opérations CRUD, les contrôleurs web opèrent directement sur L'objet de domaine POJOs (ils fonctionnent comme des entités dans ce contexte), et il n'y a pas de niveau de service. Dans les cas où il ya une sorte de coordination nécessaire entre les objets de domaine, vous pouvez avoir un service bean handle que, avec @Transaction comme par tradition. Vous pouvez définir la propagation de la transaction sur les objets de domaine à quelque chose comme REQUIRED de sorte que les objets de domaine utilisent toutes les transactions existantes, telles que les transactions qui ont été lancées au haricot de service.

techniquement, cette technique fait appel à AspectJ et <context:spring-configured /> . Roo utilise des définitions D'Inter-types pour séparer la sémantique de l'entité (transactions et persistance) des objets de domaine (essentiellement des champs et des méthodes d'affaires).

37
répondu Willie Wheeler 2017-11-21 10:14:07

je place le @Transactional sur la couche @Service et fixe rollbackFor toute exception et readOnly pour optimiser davantage la transaction.

par défaut @Transactional ne cherchera que RuntimeException (Exceptions non vérifiées), en réglant le roll-back à Exception.class (Exceptions vérifiées) il retournera pour n'importe quelle exception.

@Transactional(readOnly = false, rollbackFor = Exception.class)

voir exceptions vérifiées et non vérifiées .

29
répondu user2601995 2017-11-21 11:06:59

ou est-ce logique d'annoter les deux"couches"? - cela n'a pas de sens d'annoter à la fois la couche service et la couche dao - si l'on veut s'assurer que la méthode DAO est toujours appelée (propagée) à partir d'une couche service avec propagation" obligatoire " dans DAO. Cela fournirait une certaine restriction pour que les méthodes DAO ne soient pas appelées à partir de la couche UI (ou des contrôleurs). De plus , lorsque l'unité teste la couche de L'OAC en particulier, le fait d'avoir annoté L'OAC permettra également de s'assurer qu'elle est testé pour la fonctionnalité transactionnelle.

17
répondu tweekran 2017-11-21 11:09:06

de plus, Spring recommande d'utiliser uniquement l'annotation sur les classes de béton et non les interfaces.

http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

15
répondu davidemm 2010-01-12 15:57:03

à des fins De Transaction dans la base de données

la plupart du temps j'ai utilisé @Transactional dans DAO juste au niveau de la méthode, donc la configuration peut être spécifiquement pour une méthode / en utilisant par défaut (requis)

  1. la méthode de DAO qui obtient le fetch de données (select .. ) - n'ont pas besoin de @Transactional cela peut conduire à certains frais généraux en raison de intercepteur de transaction / et proxy AOP qui doivent être exécutés comme bien.

  2. les méthodes de DAO qui insèrent / mettent à jour obtiendront @Transactional

très bon blog sur transctional

pour le niveau d'application -

J'utilise transactional pour Business logic je voudrais pouvoir revenir en arrière en cas d'erreur inattendue

@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){

    try {    
        //service logic here     
    } catch(Throwable e) {

        log.error(e)
        throw new MyApplicationException(..);
    }
}
13
répondu lukass77 2017-04-23 19:25:46

habituellement, on devrait mettre une transaction à la couche de service.

Mais comme indiqué précédemment, l'atomicité de l'opération est ce que nous dit où une annotation est nécessaire. Ainsi, si vous utilisez des cadres comme Hibernate, où un simple " save/update/delete/...modification " l'opération sur un objet a le potentiel de modifier plusieurs lignes dans plusieurs tables (en raison de la cascade à travers le graphe d'objet), bien sûr, il devrait également y avoir une gestion des transactions sur ce méthode DAO spécifique.

12
répondu yannick555 2011-01-26 08:20:56

il vaut mieux l'avoir dans la couche service! Cela est clairement expliqué sur l'un des articles que je suis tombé sur hier! Voici le lien que vous pouvez consulter!

7
répondu sundary 2010-05-07 14:42:54

@Transactional les Annotations doivent être placées autour de toutes les opérations qui sont inséparables. En utilisant @Transactional la propagation de transaction sont traitées automatiquement.Dans ce cas,si une autre méthode est appelée par la méthode courante, alors cette méthode aura l'option de joindre l'opération en cours.

donc prenons exemple:

nous avons 2 modèles i.e. Country et City . Cartographie relationnelle de Country et City modèle est comme un Country peut avoir plusieurs villes, donc la cartographie est comme,

@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;

Ici, Pays associé à plusieurs villes de chercher le Lazily . Alors voici le rôle de @Transactinal quand nous extrayons L'objet de Pays De La base de données alors nous obtiendrons toutes les données de L'objet de pays mais ne pas obtenir L'ensemble des villes parce que nous allons chercher des villes LAZILY .

//Without @Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //After getting Country Object connection between countryRepository and database is Closed 
}

quand nous voulons accéder ensemble de villes de pays objet, puis nous aurons des valeurs null dans ce Jeu parce que l'objet de Définir créé que cet Ensemble n'est pas initialiser, il y a des données pour obtenir les valeurs de Set, nous utilisons des @Transactional c'est à dire,

//with @Transactional
@Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
   Object object = country.getCities().size();   
}

donc essentiellement @Transactional est Service peut faire plusieurs appels en une seule transaction sans fermer la connexion avec le point final.

5
répondu Harshal Patil 2015-04-27 12:05:41

tout d'abord définissons où nous devons utiliser transaction ?

je pense que la bonne réponse est - quand nous devons nous assurer que la séquence des actions sera terminée ensemble comme une opération atomique ou aucun changement ne sera fait même si l'une des actions échoue.

c'est une pratique bien connue de mettre la logique des affaires dans les services. Ainsi les méthodes de service peuvent contenir des actions différentes qui doivent être effectuées comme un seul unité logique de travail. Si tel est le cas, cette méthode doit porter la mention transactionnel . Bien sûr, toutes les méthodes ne nécessitent pas une telle limitation, de sorte que vous n'avez pas besoin de marquer tout le service comme transactionnel .

et même plus - n'oubliez pas de prendre en compte que @Transactional évidemment, peut réduire la performance de la méthode. Pour avoir une vue d'ensemble, il faut connaître les niveaux d'isolement des transactions. Savoir cela pourrait vous aider à éviter d'utiliser @Transactional là où ce n'est pas nécessairement nécessaire.

4
répondu smaiakov 2017-05-16 14:43:31

couche de Service est le meilleur endroit pour ajouter @Transactional annotations comme la plupart de la logique commerciale présente ici, il contient niveau de détail du comportement de cas d'utilisation.

supposons que nous l'ajoutions à DAO et que du service nous appelions 2 classes DAO , l'une échouée et l'autre réussie , dans ce cas, si @Transactional n'est pas sur le service une DB commit et l'autre se retournera.

par conséquent, je recommande d'utiliser cette annotation avec sagesse et de ne l'utiliser qu'à la couche Service.

Github du projet - java-algos

3
répondu VishalTambe 2018-03-23 15:58:43

idéalement, la couche de Service(Gestionnaire) représente la logique de votre entreprise et devrait donc être annotée de @Transactional .La couche de Service peut faire appel à un OAD différent pour effectuer des opérations de RS. Supposons que vous avez N nombre D'opérations de L'OFA dans une méthode de service. Si votre première opération DAO a échoué, d'autres peuvent encore être passés et vous finirez par un État de DB incohérent. Annoter la couche Service peut vous sauver de telles situations.

2
répondu salsinga 2017-03-06 03:14:35

je préfère utiliser @Transactional sur la couche services au niveau de la méthode.

1
répondu Spark-Beginer 2017-03-06 03:14:46

@Transactional utilisations dans la couche service qui est appelée en utilisant la couche contrôleur ( @Controller ) et la couche service appel à la couche OFA ( @Repository ) I. e opération liée à la base de données.

1
répondu Satish Suradkar 2017-03-06 03:15:07

enter image description here

le @Transactional doit être utilisé sur la couche de service car il contient la logique opérationnelle. La couche DAO n'a généralement que des opérations CRUD de base de données.

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

Spring doc: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html

1
répondu Alin 2018-02-11 12:05:55

il est préférable de conserver @Transactional dans une couche intermédiaire séparée entre la couche OAC et la couche Service. Depuis, le rollback est très important, vous pouvez placer toutes vos manipulations de base de données dans la couche intermédiaire et écrire la logique d'affaires dans la couche de service. La couche intermédiaire interagira avec vos couches DAO.

cela vous aidera dans de nombreuses situations comme ObjectOptimisticLockingFailureException - cette exception se produit seulement après votre La Transaction est terminée. Donc, vous ne pouvez pas l'attraper dans la couche du milieu, mais vous pouvez prendre dans votre couche de service maintenant. Cela ne serait pas possible si vous avez @Transactional dans la couche de Service. Bien que vous pouvez attraper dans le contrôleur, mais le contrôleur doit être aussi propre que possible.

si vous envoyez du courrier ou des sms dans un thread séparé après avoir terminé toutes les options enregistrer,supprimer et mettre à jour, vous pouvez le faire en service après la Transaction est terminée dans votre couche intermédiaire. Encore une fois, si vous mentionnez @Transactional dans la couche service, votre courrier passera même si votre transaction échoue.

ainsi, le fait d'avoir une couche Middle @Transaction vous aidera à améliorer votre code et à le gérer facilement. Autrement, Si vous utilisez DAO layer, vous ne pouvez pas être en mesure de faire reculer toutes les opérations. Si vous utilisez la couche de Service, vous devrez peut-être utiliser AOP (Aspect Oriented Programming) dans certains cas.

0
répondu Nabin Kumar Khatiwada 2018-08-02 09:07:32