JPA 实体中的预/后加载更新
Posted
技术标签:
【中文标题】JPA 实体中的预/后加载更新【英文标题】:Pre/post load update in the JPA entity 【发布时间】:2014-12-04 11:50:27 【问题描述】:我在 Spring Data JPA 和 Hibernate 中有项目。
有两个 JPA 实体 - 用户和作业。每个用户有多个工作。每个作业都有字段状态。创建新作业时,会向远程服务器发送一个新请求,并以 IN PROGRESS 状态保存作业。
更新后的状态可以通过远程服务器的ID查询。请求的业务逻辑应该是总是返回存储的状态,但是当Job处于IN PROGRESS状态时,应该向远程服务器查询更新状态,之后应该存储。
应该解释我意图的伪代码:
@Entity
class User
private long id;
private String username;
private Collection<Jobs> jobs;
@Entity
class Job
private long id;
private User user;
private Status status;
@Inject
private JobRepository jobRepository;
@PrePersist
private setDefaultStatus()
status = IN_PROGESS;
@PostLoad
private checkUpdatedStatus()
if (this.status == IN_PROGESS)
this.status = askRemoteServerForJobStatus(this.id);
jobRepository.save(this);
伪代码用法:
userRepsitory.find(1).jobs // should trigger checkUpdatedStatus
jobsRepository.findAll() // should trigger checkUpdatedStatus
我认为在 Job 实体中包含 jobRepository 依赖项不是一个好习惯(如伪代码所示),因此我当前的实现在存储库中完成了所有这些 - 我有像 findAll() 这样的方法调用类似 PostLoad/checkUpdatedStatus 的方法。但我也从所有其他存储库中调用它,例如用户存储库,它也获取作业项。
在我看来,这是一个非常合理的用例,所以我不相信,没有更好的方法可以做到这一点。有没有人做过类似的事情?如果你能让我走上正轨,我会非常高兴。
谢谢你, vlastikcz
【问题讨论】:
看起来不像是正确的方法。如果远程服务器无法通过状态更新进行回调,我会考虑编写一个计划任务,该任务会定期轮询远程服务器以查询当前标记为“进行中”的任何作业的状态并相应地更新。 【参考方案1】:将存储库注入实体不是一个好的举措。实体是持久结构,存储库应该管理实体,而不是相反。考虑事务分界和瞬态/分离实例。
有一种更好的方法可以在添加实体时调用某个登录名。您可以使用 event listener for this。您可以配置一个负载侦听器,它也是一个 Spring bean,因此您可以在此侦听器中注入其他服务/存储库。
【讨论】:
【参考方案2】:最后,@Alan 的评论让我重新思考,我想出了不同的方法。
创建 Job 后,我启动一个异步任务,它只是轮询远程服务器直到它收到结果。
像这样:
@HandleAfterCreate
public void addNewRemoteJob(Job job)
remoteJobDispatcher.sendRequest(job);
remoteJobDispatcher.waitForTheResult(job);
class RemoteJobDispatcher
@Async
public void waitForTheResult(Job job)
while(true)
status = askRemoteServerForJobStatus(job)
if (status != IN_PROGRESS)
job.setStatus(status);
jobRepository.save(job);
return;
sleep(2000);
可能有类似的计划或启动作业来处理可能的意外应用程序状态,但没关系。
谢谢!
【讨论】:
以上是关于JPA 实体中的预/后加载更新的主要内容,如果未能解决你的问题,请参考以下文章
如何使用条件(where子句)更新实体并在spring数据jpa中的方法响应中获取更新的实体