6.9.3 Database ItemWriters

虽然文本文件和XML都有自己特定的 ItemWriter, 但数据库和他们并不一样。这是因为事务提供了所需的全部功能。 对于文件来说 ItemWriters 是必要的, 因为如果需要事务特性,他们必须充当这种角色, 跟踪输出的 item,并在适当的时间 flushing/clearing。使用数据库时不需要这个功能,因为写已经包含在事务之中。 用户可以自己创建实现ItemWriter接口的 DAO, 或使用一个处理常见问题的自定义ItemWriter,无论哪种方式,都不会有任何问题。 需要注意的一件事是批量输出时的性能和错误处理能力。 在使用hibernate作为ItemWriter 时是最常见的, 但在使用Jdbc batch 模式时可能也会存在同样的问题。 批处理数据库输出没有任何固有的缺陷,如果我们注意 flush 并且数据没有错误的话。 但是,在写出时如果发生了什么错误,就可能会引起混乱,因为没有办法知道是哪个item引起的异常, 甚至是否某个单独的 item 负有责任,如下图所示:

刷新缓冲时出错

如果 items 在输出之前有缓冲, 则遇到任何错误将不会立刻抛出, 直到缓冲区刷新之后,提交之前才会抛出。例如, 我们假设每一块写出20个item, 第15个 item 会抛出 DataIntegrityViolationException。如果与 Step 有关, 则20项数据都会写入成功, 因为没有办法知道会出现错误,直到全部写入完成。一旦调用 Session#flush(), 就会清空缓冲区buffer, 而异常也将被放出来。 在这一点上, Step无能为力, 事务也必须回滚。 通常, 异常会导致 item 被跳过(取决于 skip/retry 策略), 然后该item就不会被输出。 然而,在批处理的情况下, 是没有办法知道到底是哪一项引起的问题, 在错误发生时整个缓冲区都将被写出。解决这个问题的唯一方法就是在每一个 item之后 flush 一下:

刷新缓冲时出错

这种用法是很常见的, 尤其是在使用Hibernate时,ItemWriter的简单实现建议, 在每次调用 write() 之后执行 flush。这样做可以让跳过 items 变得可靠, 而Spring Batch 在错误发生后会在内部关注适当粒度的ItemWriter调用。