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!
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
@marstran Peut-être comme une nouvelle abeille, je suis trop exagéré. Lol, merci ~~ – MarcuX