为什么我们不应该创建一个 Spring MVC 控制器 @Transactional? [英] Why we shouldn't make a Spring MVC controller @Transactional?

查看:33
本文介绍了为什么我们不应该创建一个 Spring MVC 控制器 @Transactional?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已经有一些关于这个主题的问题,但根本没有任何回应真正提供论据来解释为什么我们不应该制作一个 Spring MVC 控制器 Transactional.见:

There are already a few questions about the topic, but no response at all really provides arguments in order to explain why we shouldn't make a Spring MVC controller Transactional. See:

对于网络MVC Spring 应用程序应该@Transactional 去控制器还是服务?

使 Spring 3 MVC 控制器方法成为事务性

Spring MVC 控制器事务

那么,为什么?

  • 是否存在无法克服的技术问题?
  • 是否存在架构问题?
  • 是否存在性能/死锁/并发问题?
  • 有时是否需要多个单独的交易?如果是,用例是什么?(我喜欢简化的设计,对服务器的调用要么完全成功,要么完全失败.这听起来是一种非常稳定的行为)

背景:几年前,我在一个团队中工作,开发了一个在 C#/NHibernate/Spring.Net 中实现的相当大的 ERP 软件.到服务器的往返完全是这样实现的:事务在进入任何控制器逻辑之前打开,并在退出控制器后提交或回滚.交易是在框架中管理的,所以没有人需要关心它.这是一个绝妙的解决方案:稳定、简单,只有少数架构师需要关心事务问题,团队的其他成员只需要实现功能.

Background: I worked a few years ago in a Team on a quite large ERP Software implemented in C#/NHibernate/Spring.Net. The round-trip to the server was exactly implemented like that: the transaction was opened before entering any controller logic and was committed or rollbacked after exiting the controller. The transaction was managed in the framework so that no one had to care about it. It was a brilliant solution: stable, simple, only a few architects had to care about transaction issues, the rest of the team just implemented features.

在我看来,这是我见过的最好的设计.当我尝试使用 Spring MVC 重现相同的设计时,我陷入了延迟加载和事务问题的噩梦中,并且每次都得到相同的答案:不要使控制器具有事务性,但为什么呢?

From my point of view, it is the best design I have ever seen. As I tried to reproduce the same design with Spring MVC, I entered in a nightmare with lazy-loading and transaction issues and every time the same answer: don't make the controller transactional, but why?

在此先感谢您提供有根据的答案!

Thank you in advance for your founded answers!

推荐答案

TLDR:这是因为只有应用程序中的服务层具有识别数据库/业务事务范围所需的逻辑.控制器和持久层的设计不能/不应该知道事务的范围.

TLDR: this is because only the service layer in the application has the logic needed to identify the scope of a database/business transaction. The controller and persistence layer by design can't/shouldn't know the scope of a transaction.

控制器可以@Transactional,但确实是一个普遍的建议,只使服务层是事务性的(持久层也不应该是事务性的).

The controller can be made @Transactional, but indeed it's a common recommendation to only make the service layer transactional (the persistence layer should not be transactional either).

这样做的原因不是技术可行性,而是关注点分离.控制器的职责是获取参数请求,然后调用一个或多个服务方法并将结果组合在一个响应中,然后发送回客户端.

The reason for this is not technical feasibility, but separation of concerns. The controller responsibility is to get the parameter requests, and then call one or more service methods and combine the results in a response that is then sent back to the client.

因此控制器具有请求执行协调器的功能,并将域数据转换为客户端可以使用的格式,例如 DTO.

So the controller has a function of coordinator of the request execution, and transformer of the domain data to a format the client can consume such as DTOs.

业务逻辑驻留在服务层,持久层只是从数据库来回检索/存储数据.

The business logic resides on the service layer, and the persistence layer just retrieve / stores data back and forth from the database.

数据库事务的范围既是一个业务概念,也是一个技术概念:在一个账户转账中,一个账户只能借另一个账户贷记等,所以只有包含业务逻辑的服务层才能真正了解银行账户转账交易的范围.

The scope of a database transaction is really a business concept as much as a technical concept: in an account transfer an account can only be debited if the other is credited etc., so only the service layer that contains the business logic can really know the scope of a bank account transfer transaction.

持久层无法知道它在什么事务中,以customerDao.saveAddress方法为例.它应该始终在自己的单独事务中运行吗?没有办法知道,这取决于调用它的业务逻辑.有时它应该在单独的事务上运行,有时只在 saveCustomer 也工作时才保存它的数据,等等.

The persistence layer cannot know what transaction it's in, take for example a method customerDao.saveAddress. Should it run in it's own separate transaction always? there is no way to know, it depends on the business logic calling it. Sometimes it should run on a separate transaction, sometimes only save it's data if the saveCustomer also worked, etc.

这同样适用于控制器:saveCustomersaveErrorMessages 应该在同一个事务中吗?您可能想要保存客户,如果失败,则尝试保存一些错误消息并向客户端返回正确的错误消息,而不是回滚所有内容,包括您想要保存在数据库中的错误消息.

The same applies to the controller: should saveCustomer and saveErrorMessages go in the same transaction? You might want to save the customer and if that fails then try to save some error messages and return a proper error message to the client, instead of rolling back everything including the error messages you wanted to save on the database.

在非事务控制器中,由于会话关闭,从服务层返回的方法返回分离的实体.这是正常的,解决方案是使用 OpenSessionInView 或执行急切获取控制器知道它需要的结果的查询.

In non transactional controllers, methods returning from the service layer return detached entities because the session is closed. This is normal, the solution is to either use OpenSessionInViewor do queries that eager fetch the results the controller knows it needs.

话虽如此,让控制器进行交易并不是犯罪,只是不是最常用的做法.

Having said that, it's not a crime to make controllers transactional, it's just not the most frequently used practice.

这篇关于为什么我们不应该创建一个 Spring MVC 控制器 @Transactional?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆