zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Atitit 趋势管理之道 attilax著
    Atitit 循环处理的新特性 for...else...
    Atitit 2017年的技术趋势与未来的大技术趋势
    atitit 用什么样的维度看问题.docx 如何了解 看待xxx
    atitit prj mnrs 项目中的几种经理角色.docx
    Atitit IT办公场所以及度假村以及网点以及租房点建设之道 attilax总结
    Atitit 工具选型的因素与方法 attilax总结
    Atitit.团队文化建设影响组织的的一些原理 法则 定理 效应 p826.v4
    Atiitt 管理方面的误区总结 attilax总结
    Atitit 未来趋势把控的书籍 attilax总结 v3
  • 原文地址:https://www.cnblogs.com/zhongxiaoze/p/13922676.html
Copyright © 2011-2022 走看看