为什么将@Transactional与@Service一起使用而不是@Controller

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么将@Transactional与@Service一起使用而不是@Controller相关的知识,希望对你有一定的参考价值。

我在堆栈溢出文章中看到很多评论我发现@Transactional与@Service或@Controller一起使用的某些事情

“通常,应该在服务层进行交易。”

“正常情况是在服务层级注释”

“认为事务属于服务层。它是了解工作单元和用例的人。如果你有几个DAO注入到需要在单个事务中协同工作的服务,那么这是正确的答案。” [Source]

使用带有@service层的@transactional的缺点

如果我有2个方法,例如saveUser()和saveEmail()(因为我将电子邮件存储在数据库中以便稍后发送 - 就像一个队列)我会在我的服务中创建一个方法saveUserAndSendEmail(用户用户),它将是事务性的。 [Source]

这意味着我在服务层中创建了许多方法而不是一个Save Generic Method,如下所示

public <T> long save(T entity) throws DataAccessException {
    Session session = sessionFactory.getCurrentSession();
    long getGenVal=(Long) session.save(entity);
    return getGenVal;
}

根据上面的解决方案,这意味着我们有很多方法,如以下LOL ..

public <T> long saveAccount(T entity)....

public <T> long saveWithAuditLog(T entity, K entity1)....

public <T> long saveWithAuditLogAndEntries(T entity, K entity, M entity)....

克服这种情况

我在@Controller中使用@Transactional,只需制作一个通用保存方法,并使用这个简单的保存方法保存所有实体/模型。如果任何方法无法保存,则控制器中的所有事务都会成功回滚。

确保@Transactional应与@Controller一起使用的其他情况

在@Controller中:

pt.save(entity1);
pt.save(entity2);
int a = 2/0;
pt.save(entity3);

如果@Transactional on Service,前2个实体成功保存,但第三个不回滚所有事务

如果@Tratroller上的@Transactional,所有事务回滚都会发生异常

为什么堆栈溢出问道,“不要在控制器中进行事务处理。将它们放在服务层类中。”? [source]

答案

您询问最佳实践,最佳实践是在服务层中标记@Transactional,因为@Controller不应该知道MVC逻辑中的数据持久性。 @Service是基于分析生成的用例构建的,并且知道工作单元,并且还在重用方面实现思考:如果从Web上下文切换到桌面(例如,或其他一些视觉前端)@Controller层不存在你没有问题,因为所有都封装在服务层。 @Service是一个契约,表示层的修改不应该要求重写@Service代码。 但是Spring不关心你的交易边界在哪里,你可以加上@Controller,但你的应用程序可能会更难维护。

我希望这很清楚。对不起,如果不是英语不是我的母语。

另一答案

其他人都知道,不鼓励界面注释

Spring建议您只使用@Transactional注释来注释具体类(以及具体类的方法),而不是注释接口。您当然可以将@Transactional注释放在接口(或接口方法)上,但这只能在您使用基于接口的代理时按预期工作。 Java注释不是从接口继承的事实意味着如果您使用基于类的代理(proxy-target-class =“true”)或基于编织的方面(mode =“aspectj”),那么事务设置是代理和编织基础设施无法识别,并且该对象不会被包装在事务代理中,这将是非常糟糕的。

另一答案

控制器牢牢地位于视图层中,可以随时更改。该服务仍然拥有工作单元,无论访问哪个视图,都应该正常运行。我的回答here仍然有效。

另一答案

我创建了一个使用其他(非事务)服务的上层服务。而上层服务是交易性的。

@Service
public class Service1Impl implements Servcie1 {
    public Object method11(){...}
    public Object method12(){...}
}

@Service
public class Service2Impl implements Service2 {
    public method21(){...}
}

public interface Service1 {
    public Object method11();
    public Object method12();
}

public interface Service2 {
    public Object method21();
}

@Transactional
public interface UpperLayerService {}

@Service
public class UpperLayerServiceImpl implements UpperLayerService {
    @Autowired
    private Service2 service2;
    @Autowired
    private Service3 service3;

    public Object doWork() {
        Object o1 = service1.method11();
        Object o2 = service1.method12();
        Object o3 = service2.method21();
        ....
        Object res = null;//...Any code
        return res;
    }
}

以上是关于为什么将@Transactional与@Service一起使用而不是@Controller的主要内容,如果未能解决你的问题,请参考以下文章

为啥将@Transactional 与@Service 一起使用而不是与@Controller 一起使用

从Transactional与Async同时使用的错误到动态代理

项目实战--@Transactional 的使用

如何将 @Transactional 与 Spring Data 一起使用?

@Transactional 与 JPA 和 Hibernate 有啥用?

@transactional注解在什么情况下会失效,为什么。