【问题标题】:intershop ORMException could not update - refresh ORMObjectintershop ORMException 无法更新 - 刷新 ORMObject
【发布时间】:2017-08-09 01:01:49
【问题描述】:

在集群的 intershop 环境中,我们会看到很多错误消息。我怀疑应用服务器之间的通信不可靠。

Caused by: com.intershop.beehive.orm.capi.common.ORMException: 
Could not UPDATE object: com.intershop.beehive.bts.internal.orderprocess.basket.BasketPO

本地应用服务器是否有安全的方式来加载最新的实例。

   BasketPO basket = null;
        try{
            BasketPOFactory factory = (BasketPOFactory) NamingMgr.getInstance().lookupFactory(BasketPOFactory.FACTORY_NAME);
            try(ORMObjectCollection<BasketPO>baskets = factory.getObjectsBySQLWhere("uuid=?", new Object[]{basketID},CacheMode.NO_CACHING);){
                if(null != baskets && !baskets.isEmpty()){
                    basket = baskets.stream().findFirst().get();
                }
            }
        }
        catch(Throwable t){
            Logger.error(this, t.getMessage(),t);
        }

ORMObject#refresh 方法有帮助吗?

    try{
        if(null != basket)
              basket.refresh();
    }
    catch(Throwable t){
        Logger.error(this, t.getMessage(),t);
    }

【问题讨论】:

  • 如果服务器看到/缓存过时的数据,很可能是服务器间通信不起作用,您无法以编程方式解决该问题。我的回答中提供了其他解释。

标签: intershop


【解决方案1】:

您遇到该错误是因为乐观锁“失败”。为了更好地理解这个问题,我将尝试解释乐观锁定是如何工作的,特别是在 Intershop ORM 层中。

在 PO 表中有一个名为 OCA 的列(OCA == 乐观控制属性?)。想象一下,两个服务器(或两个不同的线程/事务)尝试更新表中的同一行。出于性能原因,默认情况下不涉及数据库锁定(例如,通过发出 select for update)。相反,当第一个线程/服务器在其事务中成功更新行时,OCA 会增加一个。

第二个线程/服务器从创建自己的状态时就知道 OCA 的值。然后它尝试通过发出类似的查询来更新该行:

UPDATE ... OCA = OCA + 1 ... WHERE UUID = <uuid> AND OCA = <old_oca>

由于 OCA 已由第一个线程/服务器增加,因此此更新失败(实际上 - 更新 0 行)并且当 ORM 层检测到没有更新行时,将引发您在上面发布的异常。

您的问题不是服务器间通信,而是以下事实:

  • 多个服务器/线程尝试更新同一个对象;
  • 数据库中有绕过ORM层的直接更新(不太可能);

要解决这个问题,您可以:

  1. 完全避免这种情况(我强烈推荐 :-));
  2. 使用 ISH 锁定框架(非常麻烦 imHo);
  3. 使用 ISH ORM 层和 Oracle 支持的悲观锁定(注意潜在的性能问题、死锁、错误);
  4. 使用 Java 锁定 - 但由于服务器在不同的 JVM-s 中运行,这很少是一种选择;

OFFTOPIC 备注:我不知道你为什么在知道主键 (uuid) 时使用 getObjectsBySQLWhere。据我记得ORMObjectCollection-s 如果没有完全迭代,应该关闭。

更新:如果集群配置不正确,并且无法从节点接收多播,您将无法以编程方式解决问题。

【讨论】:

    【解决方案2】:

    “ORMObject.refresh()”将缓存的共享状态标记为无效。对对象的下一次访问从数据库重新加载状态。这会影响性能并增加数据库服务器负载。

    但是: 如果“refresh()”方法已分配给当前事务,则不会重新加载 PO 实例状态。

    最好调查并修复服务器通信问题。

    【讨论】:

      【解决方案3】:

      另一种可能性是它不是通信问题(我假设集群中的节点之间的多播),而是只有两个请求试图同时更新购物篮。示例二 ajax 请求更新购物篮中的内容。

      我会避免尝试“修复” orm,它只会弊大于利。而是进一步调查并回发更多信息。

      【讨论】:

        猜你喜欢
        • 2012-01-11
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        • 1970-01-01
        • 1970-01-01
        • 2013-01-29
        • 2020-01-22
        相关资源
        最近更新 更多