首页 文章

当Reader和Writer使用同一个表时,Spring批量锁定

提问于
浏览
1

我们正在评估spring批处理(版本3.0.3),为此我们做了一个简单的数据处理

Our test:

我们在一个表中有500k行,我们想要处理它更新一个字段作为“行处理”的标志

我们的工作定义是这样的:

<beans:beans xmlns="http://www.springframework.org/schema/batch"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/batch
        http://www.springframework.org/schema/batch/spring-batch.xsd"
    profile="job1">

    <job id="job1">
        <step id="step1">
            <tasklet>
                <chunk reader="itemReader"  writer="itemWriter"
                    commit-interval="#{jobParameters['commit.interval']?:'100'}" />     
            </tasklet>
        </step>
    </job>

我们使用JdbcCursorItemReader作为阅读器(查询如SELECT field1,field2 FROM table WHERE field3 ='2Process')和JdbcBatchItemWriter作为writer(UPDATE表SET field3 ='Processed'WHERE_field1 =:field1和field2 =:field2)

我们的数据库是在我们使用的表中按页面配置的DB2 / zOS

我们使用Bitronix作为事务管理器

当我们启动它时,我们正在获得此异常:

Caused by: com.ibm.db2.jcc.am.SqlException: Error for batch element #8: DB2 SQL Error: SQLCODE=-913, SQLSTATE=57033, SQLERRMC=00C9008E;00000302;DBABCD  .TSTABLE .X'000201', DRIVER=4.19.26

似乎发生异常是因为读取器的Tx与数据库的编写器的Tx不同 . 我们在第201页有一个块 .

显然,如果我们更改select的隔离级别,添加ur,批处理就完成了 .

我们的问题是,这个数据库锁可能是导致事务管理器的问题,因为bitronix不支持嵌套的trasactions?或者似乎是db2数据库和定义的锁定策略的问题

此外,我们不知道是否有一个 spring 批处理具有读取和写入同一个表的步骤的良好实践

编辑:对不起,你是对的,在我的解释中犯了大错, db2/zOS

1 回答

  • 2

    首先你好,因为你有一个页面锁定而不是一个行锁定时有一个更新强化操作,如批处理 . 陷入僵局是不可避免的 . 所以你必须接受它 . 您需要做的是创建能够以良好方式容忍它的架构 .

    首先,我强烈建议您从页面锁定切换到行锁定 . 页面锁定的想法是为极端读取密集型应用程序启用数据库 . 我严重怀疑你的应用程序是这样的,这意味着行锁定所带来的小开销是可以忽略不计的,因为它会呈现出来 .

    但是假设你没有切换页面锁定什么是你的替代品,以减少死锁:

    • 缩小页面大小!

    • 随机播放记录 . 例如,如果您使用10个线程,请不要使批处理顺序为IDS,使第一个线程选择每个第10个记录和每个第9个记录的线程 . 当您选择读者时,甚至可以通过一些随机因素对其进行排序 .

    • 使用批处理但不批处理多个记录 . 您可以尽可能减少块大小 . 这样你就可以减少总锁定系数 .

    基本上无论你做什么,你都需要思考方向,我如何确保尽可能短的交易并尽可能多地打出不同的页面 .

    但即使这样,你也无法保证至少有一个死锁没有被击中 . 这意味着您需要实现RETRY逻辑 . 这是强制性的 .

    作为结论,只需保存所有这些麻烦并配置DB2以进行行锁定 .

    可能如果是我,我会把这个块大小设置为1-2-3这样的东西,但绝对不是100 .

相关问题