2016-09-22 12 views
-1

Это вложенности проблема, пожалуйста, помогите проанализировать причиныПочему получить соединение, которое было закрыто, в результате чего «держатель нулевой» ошибка

Общее описание кода структуры:

TransactionA в некоторых из DB, а затем откройте транзакцию B. TransactionA время фиксации, чтобы вызвать пользовательский спусковой крючок, курок в открытом transactionC (PROPAGATION_REQUIRES_NEW)

enter image description here

Процесс ошибки, как это: Первый запуск правильно не ошибка, второй раз бежать, чтобы добраться до закрытого соединения, код Test выглядит так: стек

@Test 
public void testNotify() { 

    ExecutorService threadPoolExecutor = Executors.newSingleThreadExecutor(); 

    while (true) { 

     try { 
      Thread.sleep(10000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     threadPoolExecutor.execute(new Runnable() { 
      @Override 
      public void run() { 

       //The following mainCode... 

      } 
     }); 
    } 

} 

Ошибка:

Caused by: java.sql.SQLException: connection holder is null 
    at com.alibaba.druid.pool.DruidPooledConnection.checkStateInternal(DruidPooledConnection.java:1122) ~[druid-1.0.24.jar:1.0.24] 
    at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1113) ~[druid-1.0.24.jar:1.0.24] 
    at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:318) ~[druid-1.0.24.jar:1.0.24] 
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement(PreparedStatementHandler.java:75) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.statement.BaseStatementHandler.prepare(BaseStatementHandler.java:85) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare(RoutingStatementHandler.java:57) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:73) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77) ~[mybatis-3.2.8.jar:3.2.8] 
    at sun.reflect.GeneratedMethodAccessor132.invoke(Unknown Source) ~[na:na] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45] 
    at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49) ~[mybatis-3.2.8.jar:3.2.8] 
    at com.youzan.pay.assetcenter.dal.monitor.SqlMonitorManager.intercept(SqlMonitorManager.java:53) ~[assetcenter.dal-0.0.1-SNAPSHOT.jar:na] 
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:60) ~[mybatis-3.2.8.jar:3.2.8] 
    at com.sun.proxy.$Proxy60.query(Unknown Source) ~[na:na] 
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102) ~[mybatis-3.2.8.jar:3.2.8] 
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:66) ~[mybatis-3.2.8.jar:3.2.8] 
    at sun.reflect.GeneratedMethodAccessor140.invoke(Unknown Source) ~[na:na] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45] 
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2] 

Главный код:

//Open a local transaction PROPAGATION_REQUIRED 
    transactionTemplate.execute(new TransactionCallback<Boolean>() { 

      @Override 
      public Boolean doInTransaction(TransactionStatus status) { 

       AcquireOrder acquireOrder = acquireOrderRepository.active(payResult.getAcquireNo()); 

       // Do some set... 
        acquireOrderRepository.reStore(acquireOrder); 
       } 

       //1. Look at the following 
        transactionActivityService.start("assetcenter", "", new HashMap<>()); 

        //... Some of the code to construct command 

        //2.Look at the following 
        transactionActivityService.enrollAction(SETTLEMENT_TOPIC, 
         JSONObject.toJSONString(settleCommand)); 

        //3.Look at the following 
        transactionActivityService.enrollAction(CHARGE_TOPIC, JSONObject.toJSONString(payCommand)); 
       } 

       return Boolean.TRUE; 
      } 
     }); 

1 Подробный код:

try { 
      TransactionActivityRecord activity = requiredTransactionTemplate.execute(new TransactionCallbackWithoutResult() { 
      @Override 
      protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { 
       transactionActivityStore.addTransactionActivity(activityRecord); 
      } 
     }); 
      TransactionActivityContextHolder.setCurrent(activity); 
     } catch (RuntimeException e) { 
      TransactionActivityContextHolder.clear(); 
      throw e; 
     } finally { 
      if (TransactionActivityContextHolder.isActive()) { 

       //The registration of synchronizer 
       TransactionSynchronization synchronization = new FinalizeTransactionSynchronization(transactionActivityManager); 
       TransactionSynchronizationManager.registerSynchronization(synchronization); 
      } 
     } 

2,3 Детальный код:

requiredTransactionTemplate.execute(new TransactionCallbackWithoutResult() { 
      @Override 
      protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { 
       transactionActivityStore.addTransactionAction(actionRecord); 
      } 
     }); 

3 Код синхронизации (Проблема код):

public void afterCompletion(int status) { 

     boolean actionRes = doSubmitActions(actions); 

//This code raises questions. 
     if(actionRes && activity.getState() == TransactionState.INIT) { 
      transactionActivityStore.updateTransactionActivityState(activity.getTxId(),TransactionState.PREPARE); 
     } 

    } 


/** 
    * 执行事务参与者的提交 
    * @param actions 
    * @return 
    */ 
    private boolean doSubmitActions(List<TransactionActionRecord> actions) { 
     AtomicBoolean result = new AtomicBoolean(true); 
     if(actions != null && !actions.isEmpty()) { 
      actions.stream().filter(action -> action.getState() == TransactionState.INIT).forEach(action -> { 
       boolean res = dtsTransactionActionProducer 
         .push(action.getActionName(), JSON.toJSONString(action.getContext())); 
       if (res) { 
//Open a local transaction PROPAGATION_REQUIRES_NEW 
        requiresNewTransactionTemplate.execute(new TransactionCallbackWithoutResult() { 

         @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { 
          transactionActivityStore 
            .updateTransactionActionState(action.getActionId(), TransactionState.PREPARE); 
         } 
        }); 
       } else { 
        log.warn("submit transaction-action failure topic:{},context:{}", action.getActionName(), 
          action.getContext()); 
        result.compareAndSet(true,false); 
       } 
      }); 
     } 
     return result.get(); 
    } 

3 Код синхронизации (Corre кт код):

public void afterCompletion(int status) { 

     boolean actionRes = doSubmitActions(actions); 

//Put the following code in the doSubmitActions method in the requiresNewTransactionTemplate execution 
     if(actionRes && activity.getState() == TransactionState.INIT) { 
      transactionActivityStore.updateTransactionActivityState(activity.getTxId(),TransactionState.PREPARE); 
     } 

    } 
+0

Ваша диаграмма неправильно. Круг не выполняется внутри транзакции A, он работает * после завершения транзакции A (она называется 'afterCompletion', правильно?). Таким образом, левый код пытается «обновить db-код», когда нет контекста транзакции, что подтверждается тем фактом, что «владелец подключения» пуст («null»). – Andreas

+0

Большое спасибо. Я исправил фотографию. Процесс с ошибкой выглядит так: Первый запуск корректен без ошибок, во втором времени выполнения, чтобы перейти к закрытому соединению, я добавил тестовый код. Зато второе исполнение получит закрытое соединение. – sinory

+0

Если вы не используете PROPAGATION_REQUIRES_NEW, то до того, как соединение не будет выпущено, просто закройте, что приведет к проблеме – sinory

ответ

0

Если вы не используете PROPAGATION_REQUIRES_NEW будет до того, как соединение не может быть освобожден, просто быть закрыты, в результате чего проблемы

/** 
    * Invoked after transaction commit. Can perform further operations right 
    * <i>after</i> the main transaction has <i>successfully</i> committed. 
    * <p>Can e.g. commit further operations that are supposed to follow on a successful 
    * commit of the main transaction, like confirmation messages or emails. 
    * <p><b>NOTE:</b> The transaction will have been committed already, but the 
    * transactional resources might still be active and accessible. As a consequence, 
    * any data access code triggered at this point will still "participate" in the 
    * original transaction, allowing to perform some cleanup (with no commit following 
    * anymore!), unless it explicitly declares that it needs to run in a separate 
    * transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW} for any 
    * transactional operation that is called from here.</b> 
    * @throws RuntimeException in case of errors; will be <b>propagated to the caller</b> 
    * (note: do not throw TransactionException subclasses here!) 
    */ 
    void afterCommit(); 

 Смежные вопросы

  • Нет связанных вопросов^_^