Spring Integration - 没有查询结果的JDBC通道adaptar

时间:2015-03-27 03:52:31

标签: spring-integration

当我的查询在ResultSet内返回null或零结果时,我遇到了问题。

我有int-jdbc:inbound-channel-adapter rowMapper

<int-jdbc:inbound-channel-adapter query="SELECT * FROM ENGINE_LOGS WHERE COUNTRY_ID = 2 AND BUSINESS_ID = 100 and rownum &lt; 10"   
    channel="oracle.db.resultSet.engineLogs"
    update="" 
    row-mapper="engineLogsRowMapper"
    data-source="jdbcTemplate">
    <!-- Cron Time -->
    <int:poller fixed-rate="5" time-unit="SECONDS"></int:poller>
</int-jdbc:inbound-channel-adapter>`

当查询返回null o zero(0)结果时,行映射器类或变换器(带有输入通道:oracle.db.resultSet.engineLogs)从不调用。

如果查询在数据库中找不到记录,我是否需要在辅助数据库中执行更新,是否可以添加路由器或其他东西来解决我的问题?

此致

2 个答案:

答案 0 :(得分:1)

这是对的。使用null payload的消息对于消息传递系统没有意义,例如Spring Integration。实际上没有一个现有的消息传递协议支持null有效负载。

因此,当没有来自底层系统的数据(例如您的JDBC中的JDBC)时,许多result-aware适配器不执行任何操作是标准行为。

代码如下:

private Object poll() {
    List<?> payload = doPoll(this.sqlQueryParameterSource);
    if (payload.size() < 1) {
        payload = null;
    }
    if (payload != null && updateSql != null) {
        if (this.updatePerRow) {
            for (Object row : payload) {
                executeUpdateQuery(row);
            }
        }
        else {
            executeUpdateQuery(payload);
        }
    }
    return payload;
}

如您所见update为空时无法访问ResultSet

有一个钩子可以满足您的要求。可以使用<poller>配置<advice-chain>,其中和建议适用于Callable<Boolean>.call()中的AbstractPollingEndpoint方法。在该自定义MethodInterceptor中,您可以检查invocation.proceed()的结果,如果基础true(在我们的情况下为MessageSource)返回数据,则为JdbcPollingChannelAdapter

使用false结果,你真的可以在辅助数据库中执行UPDATE

顺便说一下,我们有一个开放的issue来支持null个有效负载。我对解决方案有一个想法,使用Java 8的Optional<?>,它可以被转换为目标对象,用于下游POJO服务激活器,变换器,分离器等。

随意添加任何评论!

<强>更新

  

如何实现此类com.service.ValidateResultAdvice?

public class ValidateResultAdvice implements MethodInterceptor {

    private JdbcTemplate jdbcTemplate;

    public Object invoke(MethodInvocation invocation) throws Throwable {
         Boolean result = (Boolean) invocation.proceed();
         if (!result) {
               this.jdbcTemplate.update(...);
         }
         return result;
    }

}

类似的东西。

答案 1 :(得分:0)

我处于类似情况,在空结果集上我需要停止相同的jdbc端点,所以这是一个使用Spring Integration 5的示例。

Spring上下文配置:

<int-jdbc:inbound-channel-adapter role="jdbc-endpoint" auto-startup="false"
        data-source="dbDataSource" channel="resultSetsIn"
        query="SELECT ... FROM ... WHERE ..."
        update="UPDATE ... SET ... WHERE id IN (:id)"
        max-rows-per-poll="1">

    <int:poller fixed-rate="5000">
        <int:advice-chain>
            <bean class="services.EmptySourceService" />
        </int:advice-chain>
    </int:poller>

</int-jdbc:inbound-channel-adapter>

建议实施:

package services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.aop.AbstractMessageSourceAdvice;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.support.SmartLifecycleRoleController;
import org.springframework.messaging.Message;

public class EmptySourceService extends AbstractMessageSourceAdvice {

    @Autowired
    private SmartLifecycleRoleController roleController;

    @Override
    public boolean beforeReceive(MessageSource<?> source) {
        return true;
    }

    @Override
    public Message<?> afterReceive(Message<?> result, MessageSource<?> source) {
        if(result == null) {
            // empty query result logic
            roleController.stopLifecyclesInRole("jdbc-endpoint");
        }

        return result;
    }

}

端点停止按照Endpoint roles中的说明完成。