java - 为什么保存方法需要使用已经存在的EntityManager?
问题描述
最近我遇到了一个关于从方法更新实体的问题,即使从方法调用时它可以无缝工作@Scheduled
,它也会失败并出现异常。这是相关的例子:org.hibernate.TransientPropertyValueException: object references an unsaved transient instance
@RestController
有问题的方法(为简洁起见,省略了类的其他部分):
@Service
public class AnonymizationService
{
private final ItemRepository itemRepository;
public Result anonymizeItemsOlderThan(int days) {
List<Item> data = itemRepository.findAllByCreatedDateBeforeAndAnonymizationDateIsNull(Instant.now().minus(days, ChronoUnit.DAYS));
List<String> itemsAnonymized = new ArrayList<>(data.size());
data.forEach(item -> itemsAnonymized.add(itemRepository.save(item.anonymize()).getRequestId()));
return Result.builder().anonymizedItems(itemsAnonymized).build();
}
}
@RestController
调用者(同样省略了大部分内容):
@RestController
public class DataAnonymizationAPI
{
private final AnonymizationService anonymizationService;
@PutMapping(path = "${datadeletion.path:/anonymize}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Result> anonymizeAll(@Valid DataDeletionRules dataDeletionRules) {
return ResponseEntity.ok(anonymizationService.anonymizeItemsOlderThan(dataDeletionRules.getMinimunAge()));
}
}
同样,当像上面那样使用时,它工作得很好。当AnonymizationService#anonymizeItemsOlderThan()
从以下@Scheduled
方法调用时会出现问题:
@Component
public class DataDeletionTasks
{
private final AnonymizationService anonymizationService;
private final DataAnonymizationProperties properties;
@Scheduled(cron = "${datadeletion.anonymization.schedule}")
public void anonymizeItemsPeriodically() {
anonymizationService.anonymizeItemsOlderThan(properties.getAnonymization().getMinAge());
}
}
在这种情况下,它会失败,但上面提到的异常 ( org.hibernate.TransientPropertyValueException
)。
将日志级别更改为 DEBUG 并仔细分析后,没有任何意外发生:
- 当
@RestController
使用现有方法调用方法EntityManager
并创建事务时:
o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1702787226<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
- 当从方法调用方法时,会创建
@Scheduled
一个新方法:EntityManager
o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(644498403<open>)] for JPA transaction
当然,我的直觉是添加立即解决它@Transactional
的Anonymization#anonymizeItemsOlderThan()
方法,但为什么呢?
为什么它在一种情况下有效,而在另一种情况下无效?为什么saveAndFlush()
必须首先使用EntityManager
用于检索实体的相同来执行?
这种情况让我觉得我的知识在一个非常基础的层面上是有缺陷的,但不知怎的却找不到一个明确的解释。无论如何,请随时向我指出可能对我有帮助的相关文献。
解决方案
推荐阅读
- c# - 对于给定的输入数组,for循环不执行
- linux - Linux 上的 Jupyter:自动将所选文本复制到剪贴板 jupyter
- android - 我是否正确理解了 Google Play Open Test Track 的流程?
- c# - C# Razor 局部页面动态更新标签文本
- git - Failed to connect to github.com port 443 with command install.sh spi
- java - How to replace sun.awt.AppContext used to shutdown ExecutorService instances when context is disposed?
- postgresql - 如何在tomcat连接中定义模式属性
- c# - How to wait for Window content to resize before showing the window in C#?
- python - Deleting a specific element inside nested python dictionaries
- java - Serializing / Deserializing Polymorphic Container Objects Containing Other Polymorphic Container Objects To Json