• NCC 事务


    NC事务
    1.NC中新建独立事务
    NC中接口方法命名为method__RequiresNew(Object param) throws Exception ,后续步骤同新建NC组件一样——实现接口,在upm中注册接口。

    public interface IGuanyiBillFilterService {

    /**
    * 更新已处理的单据记录
    * @param records
    */
    void updateBillRecord__RequiresNew(List<GuanYiErpBillRecord> records) throws DAOException;
    

      

    代码中调用事务,需通过NCLocator进行远程组件调用事务才生效,直接调用不会新建事务。

    2.NC事务原理
    当进行远程组件调用时会使用动态代理执行目标方法,其中会判断方法名是否具有_RequiresNew后缀来决定是否新建事务

    public class CMTEJBServiceHandler implements InvocationHandler {
          ... public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (method.getName().endsWith("_RequiresNew")) { return this.cmtProxy.delegate_RequiresNew(this.wrapped, method, args); } return this.cmtProxy.delegate(this.wrapped, method, args); } catch (Throwable e) { Throwable lastEJBException = getLastEJBException(e); if (lastEJBException == null) { throw e; } if (lastEJBException.getCause() != null) { throw lastEJBException.getCause(); } throw e; } }
            ... }

      

    下一步会进入到如下方法,其中需要关注的是beforeCallMethod和afterCallMethod,其中分别新建和结束事务

     public class CMTProxy_Local
       extends BeanBase
       implements CMTProxyEjbObject
     {
      .....
       
       public Object delegate_RequiresNew(Object arg0, Method arg1, Object[] arg2)
         throws Exception
       {
         beforeCallMethod(200);
         try {
           o = _getBeanObject().delegate_RequiresNew(arg0, arg1, arg2);
         }
         catch (Exception e) {
           er = e;
         } catch (Throwable thr) {
           er = new FrameworkEJBException("Fatal unknown error", thr);
         }
         try {
           afterCallMethod(200, er);
         }
       .....
       }
       
     
       public Object delegate(Object arg0, Method arg1, Object[] arg2)
         throws Exception
       {
       ....
         beforeCallMethod(201);
         try {
           o = _getBeanObject().delegate_RequiresNew(arg0, arg1, arg2);
         }
         catch (Exception e) {
           er = e;
         } catch (Throwable thr) {
           er = new FrameworkEJBException("Fatal unknown error", thr);
         }
         try {
           afterCallMethod(201, er);
         }
        ......
       }
     }
    

      

    让我们看看里面干了啥…

    beforeCallMethod中首先判断组件是否是容器控制事务,获取事务类型和事务隔离级别后调用TransactionManager的begin方法

       protected void beforeCallMethod(int methodId)
       {
        ......
         boolean isCmt = ((HomeBase)getEJBLocalHome()).getEJBBeanDescriptor().isCmt();
         
         if (isCmt)
         {
           try
           {
             this.currentMethodTransectionType = getMethodTransectionType(methodId);
             int isolateLevel = getMethodIsolateLevelType(methodId);
             setIerpTransactionManagerProxy(TransactionFactory.getTMProxy());
             getIerpTransactionManagerProxy().begin(this.currentMethodTransectionType, isolateLevel);
           }
           catch (Exception e) {
             Logger.error("BeforeCallMethod", e);
           }
         }
         else {
           if (getIerpUserTransaction() == null) {
             setIerpTransactionManagerProxy(null);
             
             setIerpUserTransaction(TransactionFactory.getUTransaction());
           }
           
           getIerpUserTransaction().bindToCurrentThread();
         }
         
        ......
       }
    

      

    UAPTransactionManager中的begin方法,其中3是对应声明了_RequiresNew的接口方法,1是对应普通接口方法,自己debug可以跟踪到。

    1. 使用_RequiresNew方法会直接新建一个事务
    2. 不使用_RequiresNew会判断堆栈中是否已有事务,有就直接使用栈顶事务,没有就新建事务
    3. 之后封装成context,压栈
       public void begin(int transType) throws NotSupportedException, SystemException {
         switch (transType) {
         case 1: 
           if (this.tranStack.isEmpty()) {
             createTransaction(TransactionContextType.SOURCE);
           } else {
             createTransaction(TransactionContextType.JOINED);
           }
           break;
         case 3: 
           createTransaction(TransactionContextType.SOURCE);
           break;
         case 4: 
           if (this.tranStack.isEmpty()) {
             throw new SystemException();
           }
           createTransaction(TransactionContextType.JOINED);
           
           break;
         case 5: 
           if (!this.tranStack.isEmpty()) {
             throw new SystemException();
           }
           createTransaction(TransactionContextType.NULL);
           break;
         case 2: 
           if (!this.tranStack.isEmpty()) {
             createTransaction(TransactionContextType.NULL);
           } else {
             createTransaction(TransactionContextType.JOINED);
           }
           break;
         case 0: 
           createTransaction(TransactionContextType.NULL);
           break;
         case 11: 
           createTransaction(TransactionContextType.JOINED);
           try {
             setCurInvokeSavePoint();
           } catch (SQLException e) {
             throw new NotSupportedException("savePoint error!");
           }
         case 6: case 7: case 8: 
         case 9: case 10: default: 
           throw new NotSupportedException("trans type error!");
         }
         
       }
    
     private UAPTransactionContext createTransaction(TransactionContextType transType) throws 	SystemException
       {
         UAPTransaction uapTran = null;
         if (transType == TransactionContextType.SOURCE) {
           uapTran = new UAPTransaction();
         }
         if (transType == TransactionContextType.JOINED) {
           if (this.tranStack.isEmpty()) {
             throw new SystemException("no source Transaction,can not join ");
           }
           uapTran = (UAPTransaction)getTranContext().getTransaction();
         } else {
           uapTran = new UAPTransaction();
         }
         
         UAPTransactionContext tranText = new UAPTransactionContext(uapTran);
         tranText.setTransType(transType);
         this.tranStack.push(tranText);
         return tranText;
       }
    

      

      afterCallMethod同理

       protected void afterCallMethod(int methodId, Exception exception)
         throws java.rmi.RemoteException
       {
    ......
         boolean isCmt = ((HomeBase)getEJBLocalHome()).getEJBBeanDescriptor().isCmt();
         
         if (isCmt) {
           getIerpTransactionManagerProxy().end(exception);
           setIerpTransactionManagerProxy(null);
         }
         else
         {
           getIerpUserTransaction().unbindCurrentThread();
         }
    ......
       }
    

      

    UAPTransactionManager中的end方法,其中会判断目标方法是否抛出异常

       public void end(Exception ex)
       {
         IUAPTransactionManager m_tranManager = (IUAPTransactionManager)tm_local.get();
         try {
           if (ex != null) {
             if (m_tranManager.getTranContext().needRBPoint()) {
               if (!((UAPTransaction)m_tranManager.getTranContext().getTransaction()).getRollbackOnly())
               {
                 m_tranManager.rollBackToCurInvokePoint();
               }
             }
             else {
               m_tranManager.setCurTransRollBack();
             }
           }
           m_tranManager.commit();
         } catch (Exception e) {
           log.error("", e);
         }
       }
    

      

    假如抛出异常,最终会调用UAPTransaction的setRollbackOnly方法,值得注意的是这里的rollback仅仅是设置了一个回滚标志,没有真正回滚,之后会说这样会导致什么问题。

     

    最终会调用commit方法,这里的commit也不是单纯的提交,他会判断之前是否有设置回滚标志来进行统一回滚,整个事务调用到此完成。

    知道了以上事务的原理后,假如我们代码里面有这样一种场景,即便调用方法B的时候捕捉异常且不向外抛出,之后的数据库操作也会回滚。其中是因为调用方法B之后代理会将当前的事务设置一个回滚标志,当完成方法A之后,整个事务会根据回滚标志统一回滚。

    methodA__RequiresNew{
    ClassB cb = NCLocate.lookup(ClassB.class);
    try{
    cb.methodB();
    }catch(e){

    }
    //insert to db
    insertsomething();
    }


    同大多数框架一样,NC实现了JTA规范,拓展:

    https://www.jianshu.com/p/3938e7172443

    https://blog.csdn.net/u014235678/article/details/103898538

    3.checkpoint
    4.Synchronization

  • 相关阅读:
    USACO Name That Number
    USACO Milking Cows
    hdu 1540 Tunnel Warfare (线段树维护左右最长连续区间)
    Contest 1
    JNU周练1026
    树形DP
    Python和C扩展实现方法
    Python模拟C++输出流
    SkipList算法实现
    Python 迭代dict 效率
  • 原文地址:https://www.cnblogs.com/zhongxiaoze/p/13922676.html
Copyright © 2020-2023  润新知