MES项目中出现的一个事务嵌套的使用场景

昨天在MES项目中,需要在业务逻辑的几个关键点记录错误信息,需要把错误信息写入数据表. 但是由于整个业务逻辑都是包在一个事务模板里面的
比如这样的:
        WhhTransactionTemplate transactionTemplate2 = new WhhTransactionTemplate(true);
        transactionTemplate2.execute(new WhhTransactionCallback() {
            @SuppressWarnings({ "unchecked", "unused" })
            @Override
            public Object doInTransaction(){
                save_mes_do_materials_detail(batchDateList,para);
                matnrCostWithNothing(batchDateList,para,result,res);
                //省略....
                logerror(para, "原辅料消耗上传  调用sap功能出错!" + invokeResult.getInvokeResultMessage(), "消耗上传");
                //省略....
                return null;
            }
        });
导致logerror方法也被包含在事务中,一旦业务出错,事务回滚,那么链logerror方法写入的错误信息也会被回滚,导致无法记录下错误日志.
这和平时的事务嵌套就不一样,一般都是内层事务加入外层事务的,这里就需要内层事务暂时退出事务管理才行. 
 
这里就涉及到事务嵌套的问题, 外层事务是存在的这个就不用说了,那么此时logerror的逻辑应该要脱离事务环境才对,于是很自然的就想到应该使用
PROPAGATION_NOT_SUPPORTED 的传播特性.
 
之前分析过spring源码,知道在内层事务传播特性为PROPAGATION_NOT_SUPPORTED 的时候,会把外层事务挂起,把线程绑定的ConnectionHolder给清除掉,
导致内层事务里的方法需要获取Connection的时候,只能重新从dataSource获取 ,既然Connection不一样了,自然也就不受上层事务的影响. 
 
于是把logerror方法修改如下
    public void logerror(final Map para, final String info, final String errortype){
        TransactionTemplate tempTemplate= DBConnectManager.getDefaultDBConnectBean().getTransactionTemplate();
        //首先修改当前这个tempTemplate的传特性为PROPAGATION_NOT_SUPPORTED 
        tempTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
        tempTemplate.execute(new TransactionCallback() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                para.put("info", info);
                para.put("errortype", errortype);
                DataAdapter dataAdapter = new DataAdapter();
                dataAdapter.insert("insert into mes_error_info (wid,pid,errorinfo,errortype) values($wid$,0,#info#,#errortype#)",para);
                return null;
            }
        });
        //执行完之后 tempTemplate的传特性要改回PROPAGATION_REQUIRED 
        tempTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED );
    }

 

这样一来 记录错误信息的代码就不会受到外层事务的影响了,最后记得方法执行完,一定要把传播特性改回PROPAGATION_REQUIRED,毕竟tempTemplate是单例的,
如果不改回来,其他代码要事务管理的时候,就没有作用了

 

 

 
 
 
 
 
 
posted @ 2015-01-30 10:27  wz1989  阅读(2039)  评论(0编辑  收藏  举报