就我而言,我想通过调用方法“createTags()”来创建多个标签。为了测试方便,我在这个方法中只使用了@GET,没有任何参数,请不要介意。如果其中一个操作抛出异常,我希望所有操作都回滚,例如如果 t3 的 tagValue 为空,则 t1、t2 不应该存在于我的数据库中。显然,我应该在这里使用@Transactional,所以我的问题是我可以这样使用@Transactional吗?我的意思是在我的 REST 层中使用它。这是代码:
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);
}
}
}
或者我应该始终在我的服务层中使用@Transactional?我把上面的方法改成这样:
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);
}
}
}
他们都能达到我的预期。那么,我应该选择哪种方法呢?为什么?我可以改进这些方法有什么建议吗? 顺便说一句,我在 TestREST.class 和 TagService.class 中使用 CDI @RequestScoped 感谢您的帮助!
最佳答案
我觉得这个问题不是关于在哪里使用事务,而是更多关于代码的结构。
在示例中,将 @Transactional 添加到其余层将实现您想要的确切目标(根据抛出的错误保存所有标签或不保存)。问题变成了“业务逻辑应该存在于哪里?”。
如果其余端点只是一个数据收集方法,并且有一个获取数据并尝试保存数据的服务方法,那么事务注释应该存在于该级别。
我发现比我聪明得多的人经常使用两个概念。将事务注释移至有意义的最细层;并且,在具体方法上注释接口(interface)方法。后者本身并不适用于此(但我希望它将来对您有所帮助),但前者应该是您的指南。
重申一下,问题不在于 @Transactional 应该放在哪里。它应该是“保存标签的调用将在哪里执行”; @Transactional 将随之而来。
(希望这有帮助)
关于java - @Transactional 在 REST 层还是在服务层?哪个更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44247310/