我正在使用 JPA 3,带有注释(无映射文件)和提供者 org.hibernate.ejb.HibernatePersistence
我需要有乐观的并发性。
1)我试图依赖名为的标签,它没有工作。
2)所以我决定用java代码来做。我有一个 mergeServiceRequest 方法和一个 Request 类型的对象,如下所示:我启动一个事务,锁定请求对象,然后尝试从数据库中获取一个 Request 对象 newRequest,将其时间戳与当前一个请求进行比较。如果它们不匹配,我会抛出异常;如果它们匹配,那么我enter code here
用当前时间更新当前请求并将其保存到数据库中。
我需要手动锁定对象,因为通过从会话启动事务,它不会锁定数据库中的行。我写了一些java代码,显示事务不会自动锁定数据库中的记录。
这种方法的问题是查询
Request newRequest=entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
总是返回与请求相同的对象。“请求”在会话 entityManger 中,查询总是返回会话中缓存的内容。我尝试了所有五个 query.setHint 行,我仍然得到相同的结果:没有执行数据库查询,结果直接来自会话缓存。
@Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Query query = entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
//query.setHint("javax.persistence.cache.retrieveMode", "BYPASS");
//query.setHint("org.hibernate.cacheMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.cache.retrieveMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.retrieveMode", CacheMode.REFRESH);
//query.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);
Request newRequest=(Request)query.getSingleResult();
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
}
3)所以我也尝试使用另一个会话获取查询newRequest,如果我这样做,newRequest 将与请求不同。但是由于某种原因,如果我这样做了,那么即使在事务提交之后,请求对象上的锁定也不会被释放。代码如下所示
@Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Request newRequest=findRequest(request.getServiceRequestId()); // get it from another session
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
//lock on the database record is not released after this, and even after entityManager is closed
}
有人可以帮我吗?
谢谢。
丹尼尔