如何使用JPA注释获得乐观并发

时间:2012-07-06 13:03:31

标签: optimistic-locking

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

有人可以帮我吗?

感谢。

丹尼尔

0 个答案:

没有答案