java - @Transactional 在 REST 层还是在服务层?哪个更好?

标签 java rest jakarta-ee transactions cdi

就我而言,我想通过调用方法“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/

相关文章:

maven - 如何创建 Java EE 7 Maven IntelliJ 项目

java - Spring Jms 每秒发出警告消息

Java套接字服务器和客户端

java - Spring MVC + RestController 为资源提供 406

java - 使用spring for android休息POST对象

arrays - 如何使用来自 Web 服务的数组填充 TableViewCell?

java - 这段代码不应该产生 ClassCastException

java - 为什么 JTable 不显示 DefaultTableModel 中存储的任何数据?

Java 和 XA 事务挑战

java - 同一 Java EE session Bean 中的数据源和 EntityManager