1

众所周知,您必须使用以下模式来更新 ATGForm-Handlers中不继承自PurchaseProcessFormHanlder的订单:

boolean acquireLock = false;
ClientLockManager lockManager = getLocalLockManager();

try {
    acquireLock = !lockManager.hasWriteLock(profile.getRepositoryId(), Thread.currentThread());
    if (acquireLock) {
        lockManager.acquireWriteLock(profile.getRepositoryId(), Thread.currentThread());
    }

    boolean shouldRollback = false;

    TransactionDemarcation transactionDemarcation = new TransactionDemarcation();
    TransactionManager transactionManager = getTransactionManager();

    transactionDemarcation.begin(transactionManager, TransactionDemarcation.REQUIRED);

    try {
        synchronized (getOrder()) {
            ...
            ...
            ...
        }
    } catch (final Exception ex) {
        shouldRollback = true;
        vlogError(ce, "There has been an exception during processing of order: {0}", getOrder().getId());
    } finally { 
        try {
            transactionDemarcation.end(shouldRollback);
        } catch (final TransactionDemarcationException tde) {
            vlogError(tde, "TransactionDemarcationException during finally: {0}", tde.getMessage());
        } finally {
            vlogDebug("Ending Transaction for orderId: {0}", order.getId());
        }
    }
} catch (final DeadlockException de) {
    vlogError(de, "There has been an exception during processing of order: {0}", order.getId());
} catch (final TransactionDemarcationException tde) {
    vlogError(tde, "There has been an exception during processing of order: {0}", order.getId());
} finally {
    try {
        if (acquireLock) {
            lockManager.releaseWriteLock(getOrder().getProfileId(), Thread.currentThread(), true);
        }
    } catch (final Throwable th) {
        vlogError(th, "There has been an error during release of write lock: {0}", th.getMessage());
    }
}

理论上,任何FormHandlerPurchaseProcessFormHandler继承的都已经实现了以下步骤 OOTB:

  1. 获取LocalLockManager以避免并发线程修改相同的顺序:

    try {
        acquireLock = !lockManager.hasWriteLock(profile.getRepositoryId(), Thread.currentThread());
        if (acquireLock) {
            lockManager.acquireWriteLock(profile.getRepositoryId(), Thread.currentThread());
        }
    } catch (final DeadlockException de) {
        vlogError(de, "There has been an exception during processing of order: {0}", order.getId());
    }
    
  2. 创建一个新事务

    try {
        TransactionDemarcation transactionDemarcation = new TransactionDemarcation();
        TransactionManager transactionManager = getTransactionManager();
    
        transactionDemarcation.begin(transactionManager, TransactionDemarcation.REQUIRED);
    } catch (final TransactionDemarcationException tde) {
        vlogError(tde, "There has been an exception during processing of order: {0}", order.getId());
    }
    
  3. 结束正在使用的事务

    try {
        TransactionManager transactionManager = getTransactionManager();
        Transaction transaction = transactionManager.getTransaction();
    
        // If transaction is elegible for commiting: 
        transactionManager.commit();
        transaction.commit();
    
        // otherwise
        transactionManager.rollback();
        transaction.rollback();
    } catch (final Exception ex) {
        error = true;
        vlogError(ex, "There has been an exception during processing of order: {0}", order.getId());
    } finally {
        // handle the error
    }
    
  4. 释放用于事务的锁:

    finally {
        ClientLockManager lockManager = getLocalLockManager();
        lockManager.releaseWriteLock(profile.getRepositoryId(), Thread.currentThread(), true);
    }
    

根据 ATG 文档,以下方法实现了上述行为:

  1. 方法:之前设置

    在提交修改此表单处理程序属性的表单时,在设置此表单上的任何 setX 方法之前调用。如有必要,在表单提交过程开始时创建事务,可选择获取本地锁以防止多个表单创建可能修改同一订单的事务。

    • 步骤:1 & 2
  2. 方法:后集

    在提交修改此表单处理程序属性的表单时,在设置此表单上的任何 setX 方法后调用。提交或回滚在 beforeSet 中创建的任何事务,并释放当时获得的任何锁。

    • 步骤:3 & 4

例如,您只需处理以下程序即可更新订单:

  1. 同步将要用于的代码块 order updating以避免线程并发。

    synchronized (getOrder()) {
        ...
        ...
        ...
    }
    
  2. 执行订单修改

    synchronized (getOrder()) {
        getOrder().setXXX();
        getOrder().removeXXX();
    }
    
  3. 更新订单updateOrder将调用管道链):

    synchronized (getOrder()) {
        ...
        ...
        ...
        getOrderManager().updateOrder(order);
    }
    

这非常简单,除非您必须在以下任何情况下编辑订单:

  • 不在 的层次结构中的表单处理程序或自定义表单处理程序PurchaseProcessFormHandler
  • 助手或工具类。
  • 处理器
  • ATG REST Web 服务
  • &C

如果是这样,您将不得不在您的组件中实现事务模式。

问题!

  • 是否有任何其他已知的模式可以使用而不是使用事务模式?
  • 是否可以像 ATG 一样实现/覆盖 FormHandlers 中的beforeSet&方法afterSetPurchaseProcessFormHandler
  • 你知道其他方法吗?
4

1 回答 1

0

您上面概述的一系列步骤是更新订单的规定步骤系列。

随意以您认为有用的任何方式将其分解。只需确保在您更新订单时,您或您继承的代码已执行必要的步骤。

ATG 进行类似因式分解的一种常见方式是针对给定方法,例如X(...),您将有一个preX(...)doX(...)postX(...)方法。您可以使用preX()andpostX()方法中的所有样板代码创建一个抽象类,甚至可以声明为 final,并具有doX()声明的抽象。然后,您的组件将从抽象类继承,并且必须实现该doX()方法。您可能还需要显式处理异常。

这本质上是标准表单处理程序所做的(以不同的名称)。

例如;

public final void X(...) {
  preX(...); // call the pre method

  try {
    doX(...); // call the do method
  } catch (XException xe) {
    // handle error
  }

  postX(...); // call the post method
}

protected final void preX(...) {
  // do everything you need to do before your customer code
}

protected final void postX(...) {
  // do everything you need to do after your customer code
}

protected abstract void doX(...) throws XException;

您可以做的另一件事是定义一个包含所有样板代码的注释,而不是从抽象类继承。

您可以以类似的方式做的第三件事,但更难硬塞到您的 ATG 代码中,可能是使用第三方框架定义方面或方法调用拦截器。

然而,再一次,无论你做什么,无论你做什么,只要确保你遵循所有的步骤。

于 2016-06-20T14:05:59.867 回答