Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否从Hibernate persistenceContext缓存中排除JPA实体?_Java_Spring_Hibernate_Jpa - Fatal编程技术网

Java 是否从Hibernate persistenceContext缓存中排除JPA实体?

Java 是否从Hibernate persistenceContext缓存中排除JPA实体?,java,spring,hibernate,jpa,Java,Spring,Hibernate,Jpa,我正在用Spring和Hibernate4.3.6支持的JPA构建一个web应用程序以实现持久性。一些背景:作业结果存储在存储库中,结果控制器会对其进行检查。前端使用长轮询,因此ResultsController创建一个DeferredResult对象,然后派生一个线程来定期检查作业的完成情况,以便填写延迟结果并触发响应 private DeferredResultsResponse getResults(String idString, String runType, boolean retu

我正在用Spring和Hibernate4.3.6支持的JPA构建一个web应用程序以实现持久性。一些背景:作业结果存储在存储库中,结果控制器会对其进行检查。前端使用长轮询,因此ResultsController创建一个DeferredResult对象,然后派生一个线程来定期检查作业的完成情况,以便填写延迟结果并触发响应

private DeferredResultsResponse getResults(String idString, String runType, boolean returnOnNotDone) {
    String userId = userService.getCurrentUser();

    // Some basic checks; is the ID a valid format, etc. Not relevant,
    // but the "response" variable is set if we find a problem

    final DeferredResultsResponse deferredResult = new DeferredResultsResponse(runId, runType, userId, returnOnNotDone);
    if (response != null) {
        deferredResult.setResult(response);
    } else {
        Thread t = new Thread(() -> completeResult(deferredResult));
        t.run();
    }

    return deferredResult;
}

private void completeResult(final DeferredResultsResponse result) {
    final ResultsIdentifier id = new ResultsIdentifier(result.getJobId(), result.getRunType());
    int attemptCount = 0;
    boolean returnOnUnfinished = result.isReturnOnUnfinished();

    while (!result.hasResult() && attemptCount < MAX_ATTEMPTS) {
        attemptCount++;
 // ------- Problem line: -----------
        Optional<JobStatus> statusMaybe = jobStatusService.get(new ResultsIdentifier(result.getJobId(), result.getRunType()));

        if (!statusMaybe.isPresent()) {
            result.setResult(new ResultsResponse(null, false, null, "Unable to find job status entry."));
            continue;
        }

        JobStatus status = statusMaybe.get();
        // Incomplete job cases: sleep or respond "not done" based on the flag
        if (!status.isComplete() && returnOnUnfinished) {
            result.setResult(new ResultsResponse(false, false, null, null));
            continue;
        } else if (!status.isComplete()) {
            sleep();
            continue;
        }

        // Cases of completion: respond based on success
        // Various business logic of processing results
    }
    if (!result.hasResult()) {
        result.setResult(new ResultsResponse(true, false, null, String.format("Time out after %d checks", MAX_ATTEMPTS)));
    }
}
private DeferredResultsResponse getResults(字符串idString、字符串runType、布尔返回onNotDone){
字符串userId=userService.getCurrentUser();
//一些基本检查;ID是否为有效格式等不相关,
//但是,如果我们发现问题,“response”变量就会被设置
final DeferredResultsResponse deferredResult=新的DeferredResultsResponse(runId、runType、userId、returnOnNotDone);
if(响应!=null){
deferredResult.setResult(响应);
}否则{
线程t=新线程(()->completeResult(deferredResult));
t、 run();
}
返回延迟结果;
}
私有void completeResult(最终延迟结果响应结果){
final ResultsIdentifier id=新的ResultsIdentifier(result.getJobId(),result.getRunType());
int attemptCount=0;
布尔returnononfinished=result.isreturnonfinished();
而(!result.hassresult()&&attemptCount
问题在于:问题行上的查询永远不会报告作业状态的更改。经过一番观察,我找到了冬眠的内脏。在SessionImpl中,有一个StatefulPersistenceContext类型的字段,它保存着JobStatus对象从第一次从数据库中取出时的副本。然后在同一会话中的所有后续查询中重用该副本

现在,我想我可以通过获取当前会话并调用clear()或refresh(status)来解决这个问题。然而,对我来说,当其他地方都是通过Spring/JPA存储库进行中介时,不得不拉开JPA的帷幕,直接使用Hibernate是一种糟糕的形式。那么,有没有任何方法可以标记一个ORM XML文件,将特定类型从PersistanceContext的缓存中排除


以下是JobStatus.xml供参考:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
             version="2.0">
<entity class="project.model.JobStatus">
<attributes>
  <embedded-id name="jobIdentifier" />

  <basic name="complete" optional="false" />
  <basic name="userId" optional="false" />

  <basic name="successful" optional="true" />
  <basic name="message" optional="true" />

  <basic name="lastUpdateTime" optional="false">
    <temporal>TIMESTAMP</temporal>
  </basic>
</attributes>
</entity>
</entity-mappings>

时间戳
jobIdentifier是一个只包含一个没有子元素的元素

此外,以下是带有事务注释的JobStatusService:

public interface JobStatusService {

/**
 * Retrieve the statuses of all jobs for the current user.
 * @return All jobs' statuses
 */
@Transactional(readOnly = true)
Iterable<JobStatus> getAllByUser();

/**
 * Retrieve the status of a particular job
 * @param identifier the combined job ID and type
 * @return  The persisted job status
 */
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
Optional<JobStatus> get(ResultsIdentifier identifier);

/**
 * Save the passed status, subbing in the current user's ID if none is set,
 * and updating the "last updated" time
 * @param status the job status object
 * @return  The persisted status object
 */
@Transactional(readOnly = false)
@Modifying
JobStatus save(JobStatus status);

/**
 * Delete the status of a particular job
 * @param identifier the combined job ID and type
 */
@Transactional(readOnly = false)
@Modifying
void remove(ResultsIdentifier identifier);

/**
 * Remove all stored job statuses for the given user id.
 * @param userId User id
 */
@Transactional(readOnly = false)
@Modifying
void clearByUser(String userId);
公共接口JobStatusService{
/**
*检索当前用户的所有作业的状态。
*@返回所有作业的状态
*/
@事务(只读=真)
Iterable getAllByUser();
/**
*检索特定作业的状态
*@param identifier作业ID和类型的组合
*@返回持久化作业状态
*/
@事务性(readOnly=true,传播=propagation.REQUIRES\u NEW)
可选get(结果标识符);
/**
*保存已通过状态,如果未设置,则在当前用户的ID中进行子绑定,
*以及更新“上次更新”的时间
*@param status作业状态对象
*@返回持久化状态对象
*/
@事务(只读=假)
@修改
JobStatus保存(JobStatus状态);
/**
*删除特定作业的状态
*@param identifier作业ID和类型的组合
*/
@事务(只读=假)
@修改
作废删除(ResultsIdentifier标识符);
/**
*删除给定用户id的所有存储的作业状态。
*@param userId用户id
*/
@事务(只读=假)
@修改
void clearByUser(字符串userId);
ResultController创建一个DeferredResult对象,然后派生一个线程

实际上,不,它不是这样做的。你从不启动线程。你在同一个线程中执行所有操作,并且只在
completeResult()
返回延迟结果后才返回。要真正启动线程,你必须替换

t.run();

现在,为了确保问题行始终转到数据库并重新加载作业状态的新值,您应该做的是确保
jobStatusService.get()
在单独的事务中运行。使用Spring,通常通过使用

@Transactional(propagation = Propagation.REQUIRES_NEW)

FWIW这不是“hbm”文件。它是一个“orm.xml”,是JPA的一部分。真的!对不起,项目的发起人最初将它们全部命名为*.hbm.xml,尽管它就在xmlns中,但我没有费心更改名称。我尝试了一下,它似乎不起作用,传播也不受支持,听起来也很有希望。(任何使会话无效/清除/更改会话的操作!)在OP中添加了JobStatusService,以防其他批注交互不好导致您的建议失败。此外,在更正线程错误(感谢您发现!)后,我发现
completeResult()
开始抛出关于根本没有会话的异常。因此
@Transactional(propagation = Propagation.REQUIRES_NEW)