[英]JPA Spring Data entity to be used outside of transaction
I have a Spring Boot application with a service that returns a Spring Data entity that is exposed to a controller.我有一个带有服务的 Spring Boot 应用程序,该服务返回一个暴露给控制器的 Spring Data 实体。 The problem is that I know it's not a good idea to use entities outside of DB transactions, so what would be the best practices?
问题是我知道在数据库事务之外使用实体不是一个好主意,那么最佳实践是什么?
Consider the following service:考虑以下服务:
@Transactional
public MyData getMyData(Long id) {
return myDataRepository.findById(id);
}
where MyData is a database @Entity
and myDataRepository
is a JpaRepository
其中 MyData 是一个数据库
@Entity
和myDataRepository
是一个JpaRepository
This service method is called from a controller class, that sends this object in JSON format to a client that calls this method.该服务方法是从控制器类调用的,控制器类以 JSON 格式将此对象发送到调用此方法的客户端。
@RequestMapping("/")
public ResponseEntity<?> getMyData(@RequestParam Long id) {
return myService.getMyData(id);
}
If I expose MyData
to a controller, then it will be exposed outside of a transaction and might cause all kind of hibernate errors.如果我将
MyData
公开给控制器,那么它将在事务之外公开,并可能导致各种休眠错误。 What are the best practices for these scenarios?这些场景的最佳实践是什么? Should I convert entity to POJO in side the service and return
MyDataPOJO
instead of MyData
in MyService
?我应该在服务
MyDataPOJO
实体转换为 POJO 并在MyService
返回MyDataPOJO
而不是MyData
吗?
Using entities outside of transactions does not necessarily lead to problems;在事务之外使用实体并不一定会导致问题; it may actually have valid use cases.
它实际上可能有有效的用例。 However, there's quite a few variables at play and once you let them out of your sight things may and will go south.
然而,有很多变数在起作用,一旦你让它们离开你的视线,事情可能会而且将会向南。 Consider the following scenarios:
考虑以下场景:
As you may see, things can get out of control very quickly.如您所见,事情很快就会失控。 Especially so when your model has to evolve: before long you're going to find yourself fiddling with JSON views,
@JsonIgnore
, entity projections and so on.特别是当您的模型必须发展时:不久您会发现自己摆弄 JSON 视图、
@JsonIgnore
、实体投影等。 Thus the rule of thumb: although it may seem tempting to cut some corners and expose your entities to external layers, it's rarely a good idea.因此,经验法则是:虽然看起来很想偷工减料并将您的实体暴露给外部层,但这很少是一个好主意。 Properly designed solution always has a clear separation of concerns between layers:
正确设计的解决方案始终在层之间明确分离关注点:
So yeah, the short answer is: persistence entities should not be exposed to external layers.所以是的,简短的回答是:持久性实体不应该暴露给外部层。 One common technique is to use DTOs instead;
一种常见的技术是改用 DTO; besides, DTO objects provide additional abstraction layer in case you need to change your entities but leave API intact or vice versa.
此外,DTO 对象提供额外的抽象层,以防您需要更改实体但保持 API 不变,反之亦然。 If at some point your DTOs happen to closely resemble your entities, there are Java bean mapping frameworks like Dozer, Orika, MapStruct, JMapper, ModelMapper etc that help to eliminate the boilerplate code.
如果在某些时候您的 DTO 碰巧与您的实体非常相似,则可以使用 Java bean 映射框架(如 Dozer、Orika、MapStruct、JMapper、ModelMapper 等)来帮助消除样板代码。
Try googling "hexagonal architecture".尝试谷歌搜索“六边形架构”。 This is a very interesting concept for designing cleanly separated layers.
这是设计干净分离层的一个非常有趣的概念。 Here's one of the articles on this subject https://blog.octo.com/en/hexagonal-architecture-three-principles-and-an-implementation-example/ ;
这是关于这个主题的一篇文章https://blog.octo.com/en/hexagonal-architecture-three-principles-and-an-implementation-example/ ; it uses C# examples but they're pretty simple.
它使用 C# 示例,但它们非常简单。
You should never leak the internal model to outside resources (in your case - the @RestController
).您永远不应该将内部模型泄漏给外部资源(在您的情况下 -
@RestController
)。 The "POJO" you mentioned is typically called a DTO (Data Transfer Object).您提到的“POJO”通常称为DTO (数据传输对象)。 The DTO can be defined as an interface on the Service-side and implemented on the Controller-side.
DTO可以定义为Service端的接口,在Controller端实现。 The Service would then - as you described - transform the internal model into an instance of the DTO, achieving looser coupling between the Controler and the Service.
然后服务将 - 正如您所描述的 - 将内部模型转换为 DTO 的实例,实现控制器和服务之间的松散耦合。
By defining the DTO-interface on the service-side, you have the additional benefit that you can optimize your persistence-acces by only fetching the data specified in the corresponding DTO-interface.通过在服务端定义 DTO 接口,您可以获得额外的好处,即您可以通过仅获取在相应 DTO 接口中指定的数据来优化持久性访问。 There is, for example, no need to fetch the
friends
of a User
if the @Controller
does not specifically requests them, thus you do not need to perform the additional JOIN
in the database (provided you use a database).例如,如果
@Controller
没有特别请求他们,则不需要获取User
的friends
,因此您不需要在数据库中执行额外的JOIN
(前提是您使用数据库)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.