使用 Spring JPA “刷新”实体后未反映更改
Posted
技术标签:
【中文标题】使用 Spring JPA “刷新”实体后未反映更改【英文标题】:Changes not reflected after "refreshing" entity with Spring JPA 【发布时间】:2018-05-30 09:01:16 【问题描述】:我正在努力“刷新”一个看起来像这样的实体 (Foo):
public class Foo
//...
@OneToMany(mappedBy = "fooRef", fetch = FetchType.LAZY)
private List<Bar> bars;
public class Bar
//...
@Column(name = "FOO_ID")
private Long fooRef;
@Column(name = "STATE")
@Enumerated(EnumType.STRING)
private State state;
作为Spring JPA doesn't implement the refresh method,我只是再次查询实体。这是它不起作用的代码,我不知道为什么:
for(int i=0; i<MAX_RETRIES; i++)
List<Bar> bars = foo.getBars();
// check bars state
if(someBarIsBad)
try
TimeUnit.SECONDS.sleep(delay);
catch (InterruptedException ignored)
else
break;
foo = fooRepo.findById(fooId); // "refresh"
目标是继续重试,直到所有柱都达到所需的状态。
我正在做的测试是在循环的最后一条指令处放置一个断点,所以当它中断时,我转到表格并将所有条的状态更改为所需的状态,然后退出循环。问题是新返回的foo
,bars
并没有反映我所做的更改。
我试图消除睡眠,但这不是问题。我认为它必须与映射有关。
【问题讨论】:
我建议问题出在fetch = FetchType.LAZY
。 bars
将在您尝试使用它们时更新。刷新for (Bar bar : foo.getBars()) sout(bar);
后尝试做这样的事情。我希望这会触发延迟初始化。
我测试了删除 LAZY 提取,但结果相同。无论如何,这应该不是问题,因为我正在检索foo
的同一范围内检索bars
。 sout
是什么意思?是jpa方法吗?
nonono,sout
是 System.out.println()
的快捷方式。删除 fetch 不正确,原因是 OneToMany
关系 - 默认 fetch 类型是 LAZY。所以这个删除没有任何改变。尝试将 fetch 从 LAZY 更改为 EAGER。是的,你是对的 - 范围相同,但区别在于直接和间接使用 Bar 实体表。
这真的很奇怪。我尝试了急切的获取,没有。我尝试直接检索barRepo.findByFooRef
,但都没有。而且我已经保证通过提交正确地进行更改。
【参考方案1】:
这很可能是因为一切都在单个事务中运行。这会导致 JPA 不会从数据库中重新加载实体,而是返回它在会话中已有的实体。
要么确保您在每次“刷新”时都处于新事务中,要么将实体从会话中逐出,因此它必须再次重新加载。
【讨论】:
有道理。但我不确定我应该如何隔离交易。我把fooRepo.findById(fooId)
包装在一个用@Transactional
注释的方法上。仍然没有给我一个更新的版本。
重要的部分是您在问题中显示的代码没有包装在用@Transactional
注释的方法中
我做了,上面的代码和getFoo(ID)
都是事务性的。还是一样的:(
好的,我知道了。我不知道隔离级别。我用 @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ)
注释了 getFoo(ID)以上是关于使用 Spring JPA “刷新”实体后未反映更改的主要内容,如果未能解决你的问题,请参考以下文章
保存后刷新并获取实体(JPA/Spring Data/Hibernate)
直接从querydsl更新数据时如何刷新Spring JPA?