1

我正在使用 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
    }

有人可以帮我吗?

谢谢。

丹尼尔

4

0 回答 0