当Reader和Writer使用同一个表

时间:2018-03-02 13:05:13

标签: spring-batch bitronix

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

我们的测试:

我们在一个表中有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 =&#39; 2Process&#39;)和JdbcBatchItemWriter作为writer(UPDATE表SET field3 =&#39; Processed&#39; 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数据库和定义的锁定策略的问题

另外,我们不知道弹簧批次是否是一个好的做法,其中有一个读取和写入同一个表格的步骤

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

1 个答案:

答案 0 :(得分:2)

您好,因为您在进行更新密集操作(例如批处理)时有页锁定而不是行锁定。陷入僵局是不可避免的。所以你必须接受它。您需要做的是创建能够以良好方式容忍它的架构。

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

但是我们假设您没有切换页面锁定什么是您的替代方案,以减少死锁的最小化:

  1. 缩小页面大小!
  2. 随机播放记录。例如,如果您使用10个线程,请不要使批处理顺序为IDS,使第一个线程选择每个第10个记录和每个第9个记录的线程。当您选择读者时,甚至可以通过一些随机因素对其进行排序。
  3. 使用批处理但不批处理多个记录。您可以尽可能减少块大小。这样你就可以减少一些锁定因素。
  4. 基本上无论你做什么,你都需要在方向上思考如何确保尽可能短的交易并尽可能多地点击不同的页面。

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

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

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