Java 在HIbernate中应用升级锁定条件时出错

Java 在HIbernate中应用升级锁定条件时出错,java,hibernate,Java,Hibernate,我正在开发一个使用oracle数据库的应用程序。要连接数据库,我正在使用Hibernate。我刚接触Hibernate,遇到了一个问题,需要一些帮助。 我的设想是: 从processingStatus(我表中的一列)为“N”的数据库中选择一些行 将这些行的ProcessingStatus更新为“U” 对数据应用一些逻辑 将ProcessingStatus更改为“Y” 我写了一个代码,如果我把它作为一个进程运行,它会工作得很好,但如果我运行同一个应用程序的多个实例,问题就会出现,不同的进程可能会选

我正在开发一个使用oracle数据库的应用程序。要连接数据库,我正在使用Hibernate。我刚接触Hibernate,遇到了一个问题,需要一些帮助。 我的设想是:

  • 从processingStatus(我表中的一列)为“N”的数据库中选择一些行
  • 将这些行的ProcessingStatus更新为“U”
  • 对数据应用一些逻辑
  • 将ProcessingStatus更改为“Y”
  • 我写了一个代码,如果我把它作为一个进程运行,它会工作得很好,但如果我运行同一个应用程序的多个实例,问题就会出现,不同的进程可能会选择相同的行进行处理,而我不希望这样做。 因此,我想锁定通过选择行返回的所有行,将其ProcessingStatus更新为“U”,然后释放锁。 为此,我在Criteria
    Criteria.setLockMode(LockMode.UPGRADE)
    中获得了一个API,我计划在运行select查询时使用该API,以便任何其他行都不会选择这些行,但问题是,当我使用此API时,我遇到了错误 错误是:

    2602 [main] WARN org.hibernate.util.JDBCExceptionReporter  - SQL Error: -11, SQLState: 37000
    2602 [main] WARN org.hibernate.util.JDBCExceptionReporter  - SQL Error: -11, SQLState: 37000
    2603 [main] ERROR org.hibernate.util.JDBCExceptionReporter  - Unexpected token: FOR in statement [select this_.CUSTOMER_ID as CUSTOMER1_2_0_, this_.MARKETPLACE_ID as MARKETPL2_2_0_, this_.PROCESSING_DATE as PROCESSING3_2_0_, this_.AMOUNT as AMOUNT2_0_, this_.LAST_SHIP_DATE as LAST5_2_0_, this_.ORDER_DATE as ORDER6_2_0_, this_.PROCESSING_STATUS as PROCESSING7_2_0_, this_.PURCHASE_ID as PURCHASE8_2_0_, this_.QUANTITY as QUANTITY2_0_ from CUSTOMERS_FIRST_ORDER this_ where this_.PROCESSING_DATE=? and this_.MARKETPLACE_ID=? and this_.PROCESSING_STATUS=? limit ? for update]
    
    有人能帮我一下吗?我没有弄错什么。如果我使用
    LockMode.READ
    ,那么它可以工作,但升级/写入模式会出错

    引发错误的代码段是:

    @SuppressWarnings("unchecked")
    @Transactional
    public List<CustomerFirstOrder> getOrders(final Date processingDate, long marketplaceID, int count) throws Exception {
        final Session session = getSession();
        final Criteria criteria = session.createCriteria(CustomerFirstOrder.class);
        criteria.add(Restrictions.eq(PROCESSING_DATE, processingDate));
        criteria.add(Restrictions.eq(MARKETPLACE_ID, marketplaceID));
        criteria.add(Restrictions.eq(PROCESSING_STATUS, ProcessingStatus.NOTPROCESSED.toString().charAt(0)));                ///Select only unprocessed rows
        criteria.setMaxResults(count); // select multiple rows
        criteria.setLockMode(LockMode.UPGRADE);
        LOGGER.debug("selecting multple row for date " + processingDate + " of marketplace " + marketplaceID + " of status " + ProcessingStatus.NOTPROCESSED);
        final List<CustomerFirstOrder> results;
        try {
                results = (List<CustomerFirstOrder>)criteria.list();
                return results;
            }
        }
    }
    
    @SuppressWarnings(“未选中”)
    @交易的
    公共列表getOrders(final Date processingDate、long marketplaceID、int count)引发异常{
    最终会话=getSession();
    最终标准=session.createCriteria(CustomerFirstOrder.class);
    标准.添加(限制.eq(处理日期,处理日期));
    标准.添加(限制.eq(市场ID,marketplaceID));
    criteria.add(Restrictions.eq(PROCESSING_STATUS,ProcessingStatus.NOTPROCESSED.toString().charAt(0));///仅选择未处理的行
    criteria.setMaxResults(count);//选择多行
    标准。设置锁定模式(锁定模式。升级);
    LOGGER.debug(“为日期“+processingDate+”市场“+marketplaceID+”状态“+ProcessingStatus.NOTPROCESSED”选择多行);
    最终结果清单;
    试一试{
    results=(List)criteria.List();
    返回结果;
    }
    }
    }
    
    在Oracle中,通过Hibernate使用limits和for update子句存在一些已知问题,这些问题至少可以追溯到几年前。看见尝试取出以下行:

    criteria.setMaxResults(count);
    

    然后再次运行测试。作为旁注,
    LockMode.UPGRADE
    在Hibernate中是不推荐的,您应该使用
    悲观写入

    Oracle不支持
    limit
    子句,因此如果Hibernate配置为使用Oracle方言,则无法使用
    limit
    子句生成查询


    因此,您需要使用正确的Oracle方言,使Hibernate为Oracle生成正确的查询。

    我还有一个问题,即何时释放此锁?当交易完成时,它会自动释放还是我必须手动解锁it@Rahul:
    锁定模式。升级
    变成
    选择。。。对于事务结束时释放的更新
    锁。我还有一个问题:何时释放此锁?当事务完成时,它会自动释放吗?或者我必须手动解锁它。您似乎正在使用声明性事务,这意味着Hibernate将自动为您管理事务,在这种情况下,当方法返回时,您的事务将结束。如果我明白你在做什么,那就不是你想要的。通常,如果在数据库上使用悲观锁,则可以管理自己的事务。此外,您应该尝试快速处理这些记录并提交结果——长时间持有DB锁会延迟应用程序的性能。