我正在使用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());
始终返回与请求相同的对象。 “request”位于会话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
}
有人可以帮我吗?
感谢。
丹尼尔