目前,我有这个代码:
@Transactional
fun apiMethod() {
val entity: SomeEntity = myRepo.find()
methodWithDbCalls1(entity)
methodWithExternalCalls(entity)
methodWithDbCalls2(entity)
}
因为我在顶层方法中使用了@Transactional
,所以所有DB操作(包括entity
)都在单个事务中运行。
现在,methodWithExternalCalls
调用一些第三方服务,这些请求需要很长时间,因此通过它阻塞整个事务不是一个好主意。因此,我只想将方法methodWithDbCalls1
和methodWithDbCalls2
Package 到@Transactional
中,而methodWithExternalCalls
根本不能在事务中运行。现在的问题是entity
当然是延迟加载的,因此,通过删除包含的事务,我开始获得惰性初始化异常。
我的问题是如何处理这个问题。我想到两个解决方案,都不理想:
- 预取那些内部方法需要的
entity
属性。这样做的缺点是外部方法会与内部方法逻辑紧密绑定。此外,看起来有点笨拙。 - 将
entity
具体化为一个合适的DTO。这看起来更简洁一些,但实际上存在同样的问题,因为"合适的DTO"再次表示为内部方法的使用量身定制。
有没有更好的解决方案?我特别感兴趣的是那些可以避免外部方法了解内部方法的内部工作方式的方法。
1条答案
按热度按时间g6ll5ycj1#
我认为您目前针对LazyInitializationException的解决方案是正确的。我唯一能提供(但不推荐)的其他解决方案是对Entity类的相关示例变量应用渴望获取。我自己会选择DTO。
但是,考虑到methodWithDbCalls1、methodWithExternalCalls和methodWithDbCalls2将根据您的示例按顺序运行,您的事务仍将被阻止,直到外部调用完成,因为事务仍将在外部方法调用中使用。从内部方法中删除事务上下文将无法解决此问题。
您可能需要考虑对外部逻辑使用非阻塞调用,可能需要一个Executor。这样,事务和所有必须在其中执行的逻辑都可以继续。如果以下数据库调用需要来自长外部请求的信息,除了等待信息之外,没有什么可做的。