【问题标题】:How JDBC:inbound-channel-adapter max-row works with select for update?JDBC:inbound-channel-adapter max-row 如何与选择更新一起使用?
【发布时间】:2019-08-26 03:53:45
【问题描述】:

我正在使用 select 进行更新查询以避免多个 JVM 重复处理,并且我在 int-jdbc:inbound-channel-adapter 中有 max-row=10

假设该表有 50,000 条记录。

spring/integration/jdbc会只锁10行还是50000行?

另外,根据文档:https://docs.spring.io/spring-integration/docs/5.2.0.M3/reference/html/jdbc.html

“建议通过供应商特定的查询选项使用结果集限制,例如 MySQL LIMIT 或 SQL Server TOP 或 Oracle 的 ROWNUM。有关详细信息,请参阅特定供应商文档。”

这意味着服务器将选择查询获取的所有记录。

    <int-jdbc:inbound-channel-adapter
        id="initial.poller"
        query="select id from transaction where status='created'"
        max-rows="10"
        update="update transaction set status='processed' where ID in (:id)"
        row-mapper="pollerRowMapper"
        data-source="dataSource" channel="transactionChannel">
        <int:poller fixed-rate="200" time-unit="MILLISECONDS">
            <int:transactional  />
        </int:poller>

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

我在调试模式下检查了只有 10 行被 jvm 锁定,其他 JVM 正在获取并处理其他记录。

1) spring/hibernate 如何与 oracle 通信以仅锁定它正在挑选的 10 条记录?

2) 如果查询中必须使用 ROWNUM,max-rows 的用途是什么?

编辑 1:我们无法同时选择 update 和 rownum。 oracle 上都不允许这些:

select * from (select id from transaction where status='created' order by id) WHERE rownum <= 10 FOR UPDATE SKIP LOCKED ;
select * from (select id from transaction where status='created' order by id FOR UPDATE SKIP LOCKED) WHERE rownum <= 10  ;

如何获得性能优化?表有数百万条记录。

【问题讨论】:

    标签: oracle spring-integration spring-jdbc


    【解决方案1】:

    查看它的 JavaDocs:

    /**
     * The maximum number of rows to query. Default is zero - select all records.
     * @param maxRows the max rows to set
     * @since 5.1
     */
    public void setMaxRows(int maxRows) {
    

    因此,我们可以假设这确实会以某种方式限制记录。这就是它在代码中的完成方式:

    return new PreparedStatementCreatorWithMaxRows(preparedStatementCreator,
                        JdbcPollingChannelAdapter.this.maxRows);
    
    ...
        @Override
        public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
            PreparedStatement preparedStatement = this.delegate.createPreparedStatement(con);
            preparedStatement.setMaxRows(this.maxRows); // We can't mutate provided JdbOperations for this option
            return preparedStatement;
        }
    

    让我们来看看那些 JavaDocs:

    /**
     * Sets the limit for the maximum number of rows that any
     * <code>ResultSet</code> object  generated by this <code>Statement</code>
     * object can contain to the given number.
     * If the limit is exceeded, the excess
     * rows are silently dropped.
     *
     * @param max the new max rows limit; zero means there is no limit
     * @exception SQLException if a database access error occurs,
     * this method is called on a closed <code>Statement</code>
     *            or the condition {@code max >= 0} is not satisfied
     * @see #getMaxRows
     */
    void setMaxRows(int max) throws SQLException;
    

    所以,这就是它受到限制的地方。即使ROWNUM 不能与FOR UPDATE 一起使用,我认为您对目前所拥有的东西是安全的。

    【讨论】:

    • 好的,所以 max-rows 会默默地删除多余的记录,并且记录锁定会以某种方式起作用,但不幸的是,max-rows 选项不适合最后一个数据集。我的轮询器设置为 200 毫秒,但没有 ROWNUM 的查询获取需要 30 分钟。
    • 是的,不过我依赖的是 max-rows。我将在此处添加 oracle 标记,但我知道 oracle 的唯一选择是使用 store proc 并且 inbound-channel-adapter 将无法运行 store proc 而不是查询...所以我被卡住了
    • 如果在 Spring 集成中支持存储过程,你怎么能被卡住:docs.spring.io/spring-integration/docs/5.2.0.BUILD-SNAPSHOT/… ?
    • 谢谢,刚刚意识到,store proc 是受支持的,但是在 store proc 中选择更新将是一个与 Spring 容器不同的事务。
    • 您可以从轮询器开始事务,因此它将传播到数据库中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    相关资源
    最近更新 更多