Dans vos exemples, cela dépend de si votre dépôt a @Transactional
ou pas.
Si oui, alors le service, (tel qu'il est) dans votre cas - ne devrait pas être utilisé. @Transactional
(puisqu'il n'y a aucun intérêt à l'utiliser). Vous pouvez ajouter @Transactional
plus tard, si vous prévoyez d'ajouter plus de logique à votre service qui traite d'autres tables / référentiels - alors il sera utile de l'avoir.
Si non - alors votre service doit utiliser @Transactional
si vous voulez vous assurer que vous n'avez pas de problèmes d'isolement, que vous ne lisez pas quelque chose qui n'est pas encore commuté par exemple.
--
Si l'on parle de référentiels en général (comme interface de collecte de crudités) :
- Je dirais : NON, vous ne devriez pas utiliser @Transactional
Pourquoi pas : si nous croire ce référentiel est en dehors du contexte de l'entreprise, et il ne devrait pas connaître la propagation ou l'isolation (niveau de verrouillage). Il ne peut pas deviner dans quel contexte de transaction il pourrait être impliqué.
les référentiels sont "sans activité" (si vous le pensez)
disons que vous avez un référentiel :
class MyRepository
void add(entity) {...}
void findByName(name) {...}
et il y a une logique d'entreprise, disons MyService
class MyService() {
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.SERIALIZABLE)
void doIt() {
var entity = myRepository.findByName("some-name");
if(record.field.equal("expected")) {
...
myRepository.add(newEntity)
}
}
}
C'est-à-dire que dans ce cas : MyService
décide dans quoi elle veut impliquer le dépôt.
Dans ce cas, avec propagation="Required", on s'assure que les DEUX méthodes de dépôt - findByName()
y add()
sera impliqué dans une transaction unique, et l'isolation="Serializable" permettra de s'assurer que personne ne peut interférer avec cela. Il gardera un verrou pour la ou les tables dans lesquelles get() et add() sont impliqués.
Mais un autre service peut vouloir utiliser MyRepository différemment, sans s'impliquer dans aucune transaction, en utilisant par exemple findByName()
qui n'est pas intéressé par une quelconque restriction pour lire tout ce qu'il peut trouver à ce moment.
- Je dirais OUI, si vous traitez votre référentiel comme un référentiel qui renvoie toujours des entités valides (pas de lectures sales), etc, (ce qui évite aux utilisateurs de l'utiliser de manière incorrecte). C'est-à-dire que votre référentiel devrait prendre en charge le problème d'isolation (concurrence et cohérence des données), comme dans l'exemple :
nous voulons (dépôt) nous assurer que lorsque nous add(newEntity)
il vérifie d'abord s'il existe déjà une entité portant le même nom, et si c'est le cas, il l'insère, le tout en une seule unité de travail verrouillée. (la même chose que ce que nous avons fait pour le niveau de service ci-dessus, mais nous ne déplaçons pas cette responsabilité vers le référentiel).
Disons qu'il ne peut pas y avoir 2 tâches avec le même nom "en cours" (règle de gestion).
class TaskRepository
@Transactional(propagation=Propagation.REQUIRED,
isolation=Isolation.SERIALIZABLE)
void add(entity) {
var name = entity.getName()
var found = this.findFirstByName(name);
if(found == null || found.getStatus().equal("in-progress"))
{
.. do insert
}
}
@Transactional
void findFirstByName(name) {...}
La deuxième est plus proche du référentiel de style DDD.
Je suppose qu'il y a plus à couvrir si :
class Service {
@Transactional(isolation=.., propagation=...) // where .. are different from what is defined in taskRepository()
void doStuff() {
taskRepository.add(task);
}
}