【问题标题】:Selecting and updating against tables in separate data sources within the same transaction选择和更新同一事务中不同数据源中的表
【发布时间】:2014-03-06 13:16:25
【问题描述】:

Spring Integration 中<jdbc:inbound-channel-adapter> 组件的属性包括data-sourcesqlupdate。这些允许针对指定数据库中的表运行单独的 SELECT 和 UPDATE 语句。两条 sql 语句将属于同一事务。

这里的限制是 SELECT 和 UPDATE 都将针对同一个数据源执行。当 UPDATE 位于不同数据源(而不仅仅是同一服务器上的不同数据库)的表上时,是否有解决方法?

我们的具体要求是选择表中具有特定时间之前时间戳的行。该时间存储在单独数据源的表中。 (它也可以存储在文件中)。如果两个 sql 语句都使用同一个数据库,那么 <jdbc:inbound-channel-adapter> 对我们来说开箱即用就可以了。在这种情况下,SELECT 可以使用存储在表 A 中的时间作为针对表 B 运行的查询中 WHERE 子句的一部分。然后将表 A 中的时间更新为当前时间,所有这些都将是一笔交易的一部分。

我的一个想法是,在适配器的sqlupdate 属性中,使用SpEL 调用bean 中的方法。为sql 定义的方法将查找存储在文件中的时间,然后返回完整的SELECT 语句。为update 定义的方法将更新同一文件中的时间并返回一个空字符串。但是,我不认为这种方法是故障安全的,因为文件的读取和写入不会是数据源正在使用的同一事务的一部分。

但是,如果保证update 仅在提交数据源事务时触发,那么这对我们有用。如果发生故障,数据库事务将提交,但文件不会被更新。然后我们会得到重复的行,但应该能够处理它。问题是文件是否已更新并且数据库事务失败。那将意味着丢失的消息,我们无法处理。

如果有人对如何处理这种情况有任何见解,我们将不胜感激。

【问题讨论】:

    标签: spring-integration


    【解决方案1】:

    使用两个不同的通道适配器和一个发布-订阅通道,或一个出站网关,后跟一个出站通道适配器。

    如有必要,在两者上游启动事务;如果您想要真正的原子性,则需要使用 XA 事务管理器和 XA 数据源。或者,您可以通过同步两个事务来接近,使它们非常接近地提交。

    请参阅Dave Syer's article "Distributed transactions in Spring, with and without XA",特别是有关 Best Efforts 1PC 的部分。

    【讨论】:

    • 谢谢。我认为这个问题可以简化:在 Spring Integration 中,确保事务完成后执行一段代码的最佳方法是什么?
    • docs.spring.io/spring-integration/reference/html/… - 将事务同步添加到轮询器并在“提交后”通道之后放置一些流。
    • 这行得通,但问题是当轮询器返回一个空的结果集时,附加到提交后通道的服务适配器没有被调用。这意味着 SELECT 语句中使用的时间戳不会被更新。然后将继续读取相同的空结果集。日志显示:“SourcePollingChannelAdapter - 在轮询期间未收到任何消息,返回 'false'。启动事务提交”。因此,即使事务被提交,轮询器返回 false 的事实似乎破坏了事务同步机制。有解决办法吗?
    • 我不会说它“破坏”了机制——它的目的是让您可以在一些实际工作完成(或失败)后采取一些行动。由于没有来自民意调查的数据,因此没有“发布处理”的消息。一种解决方法可能是继承JdbcTemplate 并覆盖<T> T query(String sql, SqlParameterSource paramSource, ResultSetExtractor<T> rse) throws DataAccessException;(这是适配器调用的方法)。您可以委托给super 并检测一个空列表并采取一些措施。使用jdbc-operations 属性将自定义模板的实例注入到适配器中。
    猜你喜欢
    • 1970-01-01
    • 2018-09-19
    • 2016-01-27
    • 1970-01-01
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多