1

我们在我们的应用程序中使用 spring poller 来轮询来自 mySQL DB 的数据并发送给第三方。该功能可以正常工作,但是当我们转移到 PRODUCTION 时,因为我们有多个 appservers ,该作业正在所有服务器上运行,我们需要在所有服务器上运行它来处理传入的请求。

轮询时间配置为每 5 秒运行一次。

但是,即使我们添加了更新语句,一条特定的记录也会在多个服务器中被拾取,因为它们同时运行。

我们有以下配置

<int-jdbc:inbound-channel-adapter id="datachannel"
        query="${sql}"
        data-source="dbDataSource" max-rows-per-poll="1" row-mapper="pollerdatamapper"
        update="update <table> set flag=1 where id =:Id">

        <int:poller fixed-rate="${pollerinterval}">
        <int:transactional/>
        </int:poller>

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

PollerService 类将为来自上述轮询器的每条记录调用如下

<int:service-activator input-channel="datachannel"
        output-channel="executerchannel" ref="pollerservice" method="getRecordFromPoller">
</int:service-activator>

公共类轮询服务 {

private static final Logger LOGGER = Logger.getLogger(PollerService.class);


public PollerDataBO getRecordFromPoller(PollerDataBO pollerDataBO)
{
  LOGGER.info("call for the Id " + Id); 
 }

您能否确认是否有任何交易设置可以限制我们在其他服务器中选择相同记录。

4

1 回答 1

0

对,SELECT ... FOR UPDATE对你来说应该是很好的解决方案:

https://docs.oracle.com/cd/E17952_01/mysql-5.1-en/innodb-locking-reads.html

你也可以试试isolation="SERIALIZABLE"for the <int:transactional/>,但我对它没有太大的信心。

另外我认为我们可以改进JdbcPollingChannelAdapter代码中的内容,例如:

if (this.updatePerRow) {
    for (Object row : payload) {
            executeUpdateQuery(row);
    }
}

并跳过那些未更新的行。

随意就此事提出JIRA

于 2018-05-07T13:26:52.993 回答