これは、なにをしたくて書いたもの?
Spring Frameworkでのトランザクション管理といえば、宣言的トランザクションを使うことが多いでしょう。
Data Access / Transaction Management / Declarative Transaction Management
一方で、宣言的トランザクションではデフォルトではRuntimeException
(とError
)がロールバック対象となり、Exception
…いわゆる
検査例外はロールバックされないことも知られています。
In its default configuration, the Spring Framework’s transaction infrastructure code marks a transaction for rollback only in the case of runtime, unchecked exceptions. That is, when the thrown exception is an instance or subclass of RuntimeException. (Error instances also, by default, result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration.
Data Access / Transaction Management / Rolling Back a Declarative Transaction
Spring Batchでは、トランザクション管理をSpring Batch側が行うということなのですが、スローされる例外がRuntimeException
なのか
Exception
なのかで挙動が変わるのかどうかが気になったので、調べてみることにしました。
Spring Batchのトランザクション管理
まずは、Spring Batchのトランザクション管理に関するドキュメントを見てみましょう。
トランザクションに関する記述は、このあたりのドキュメントに書かれているようです。
Batch Processing and Transactions
主には、チャンク指向の処理で説明が書かれています。トランザクションの単位が、チャンクというデータのまとまりになるという
話ですね。
Chunk oriented processing refers to reading the data one at a time and creating 'chunks' that are written out within a transaction boundary. Once the number of items read equals the commit interval, the entire chunk is written out by the ItemWriter, and then the transaction is committed.
Configuring a Step / Chunk-oriented Processing
たとえば、チャンクのサイズが100なら、スキップ等を考えなければデータ100件ごとにひとつのトランザクションとして扱われることに
なります。
チャンクサイズは、コミット間隔としても説明されています。
As mentioned previously, a step reads in and writes out items, periodically committing using the supplied PlatformTransactionManager. With a commit-interval of 1, it commits after writing each individual item. This is less than ideal in many situations, since beginning and committing a transaction is expensive. Ideally, it is preferable to process as many items as possible in each transaction, which is completely dependent upon the type of data being processed and the resources with which the step is interacting.
Configuring a Step / Chunk-oriented Processing / The Commit Interval
ロールバック制御の説では、ItemWriter
によって例外がスローされるとロールバックされることが書かれています。
By default, regardless of retry or skip, any exceptions thrown from the ItemWriter cause the transaction controlled by the Step to rollback.
Configuring a Step / Chunk-oriented Processing / Controlling Rollback
こう読むと、ItemReader
とItemProcessor
はどうなんでしょうね?
ItemReader
に関しては、JMSキューを扱う場合などのトランザクショナルなリソースを扱う際に、キューから取得したメッセージを
戻さないようにバッファリングしないよう設定する方法も書かれています。
Configuring a Step / Chunk-oriented Processing / Controlling Rollback / Transactional Readers
こう見ると、ItemReader
もトランザクションの範囲に含まれていそうですね。そうであって欲しいですが。
ちなみに、Listenerとトランザクションの関係についてもドキュメントに書かれています。
Configuring a Step / Chunk-oriented Processing / Intercepting Step Execution
チャンクに対してTasklet
の場合は、シンプルにトランザクションにラップされることが書かれています。
Each call to a Tasklet is wrapped in a transaction.
Configuring a Step / TaskletStep
一方で、こちらのドキュメント…付録にはバッチの構成のバリエーションとトランザクションの関係がまとめられていますが。
Batch Processing and Transactions
シンプルな処理パターンでは、ここまで見てきた情報(特にチャンク)が簡潔にまとめられているだけですね。
Appendix A: Batch Processing and Transactions / Simple Batching with No Retry
ドキュメントから得られる情報はこれくらいなので、あとは実際に動かして確認してみるとしましょう。
お題
今回のお題は、こちら。
- チャンクと
Tasklet
、それぞれでJob
を構成する Job
の内容は、List
に定義したデータ10件をJPAでデータベースに書き込む処理とする- チャンク
- データを10件用意して、チャンクサイズは3件とする
- 一定の件数を処理した後で、
RuntimeException
およびException
をItemReader
、ItemProcessor
、ItemWriter
それぞれから例外をスローして動作を確認する
Tasklet
- データを10件用意して一定の件数を処理した後で、
RuntimeException
およびException
をTasklet
から例外をスローして動作を確認する
- データを10件用意して一定の件数を処理した後で、
このバリエーションを確認してみます。
環境
今回の環境は、こちら。
$ java --version openjdk 17.0.3 2022-04-19 OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1) OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing) $ mvn --version Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.3, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-110-generic", arch: "amd64", family: "unix"
データベースには、MySQLを使用します。MySQLは、172.17.0.2で動作しているものとします。
$ mysql --version mysql Ver 8.0.29 for Linux on x86_64 (MySQL Community Server - GPL)
プロジェクトを作成する
まずは、Spring Bootプロジェクトを作成します。依存関係には、batch
、data-jpa
、mysql
を加えました。
$ curl -s https://start.spring.io/starter.tgz \ -d bootVersion=2.7.0 \ -d javaVersion=17 \ -d name=batch-transaction \ -d groupId=org.littlewings \ -d artifactId=batch-transaction \ -d version=0.0.1-SNAPSHOT \ -d packageName=org.littlewings.spring.batch \ -d dependencies=batch,data-jpa,mysql \ -d baseDir=batch-transaction | tar zxvf -
プロジェクト内に移動。
$ cd batch-transaction
生成されたソースコードは、削除しておきます。
$ rm src/main/java/org/littlewings/spring/batch/BatchTransactionApplication.java src/test/java/org/littlewings/spring/batch/BatchTransactionApplicationTests.java
<properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
今回のテーブル定義は、こちらにしました。書籍をお題にします。
src/main/resources/schema.sql
drop table if exists book; create table book ( isbn varchar(14), title varchar(100), price int, primary key(isbn) );
対応するJPAのEntity。
src/main/java/org/littlewings/spring/batch/Book.java
package org.littlewings.spring.batch; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "book") public class Book { @Id @Column(name = "isbn") String isbn; @Column(name = "title") String title; @Column(name = "price") Integer price; public static Book create(String isbn, String title, Integer price) { Book book = new Book(); book.setIsbn(isbn); book.setTitle(title); book.setPrice(price); return book; } // getter/setterは省略 }
main
クラス。
src/main/java/org/littlewings/spring/batch/App.java
package org.littlewings.spring.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class App { public static void main(String... args) { SpringApplication.run(App.class, args); } }
設定。
src/main/resources/application.properties
spring.datasource.url=jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8 spring.datasource.username=kazuhira spring.datasource.password=password spring.sql.init.mode=always spring.batch.jdbc.initialize-schema=always logging.level.org.springframework.batch.core.step=debug logging.level.org.springframework.transaction=debug
アプリケーションが使用するテーブルや、Spring Batchが使用する使用するテーブルは起動時に作成するようにしました。
あとは、チャンクとTasklet
のJob
を作成しつつ動作確認していきましょう。
チャンク
チャンクを構成する、ItemReader
、ItemProcessor
、ItemWriter
を以下のように作成。
ItemReader
。
src/main/java/org/littlewings/spring/batch/BookItemReader.java
package org.littlewings.spring.batch; import java.util.Iterator; import java.util.List; import org.springframework.batch.item.NonTransientResourceException; import org.springframework.batch.item.ParseException; import org.springframework.batch.item.UnexpectedInputException; import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; import org.springframework.batch.item.support.AbstractItemStreamItemReader; public class BookItemReader extends AbstractItemStreamItemReader<Book> { Iterator<Book> bookIterator; int currentCount = 0; public BookItemReader() { List<Book> books = List.of( Book.create("978-4798142470", "Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発", 4400), Book.create("978-4774182179", "[改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ", 4180), Book.create("978-1492076988", "Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications", 6265), Book.create("978-1484237236", "The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud", 7361), Book.create("978-4798161488", "MySQL徹底入門 第4版 MySQL 8.0対応", 4180), Book.create("978-4797393118", "基礎からのMySQL 第3版 (基礎からシリーズ)", 6038), Book.create("978-4873116389", "実践ハイパフォーマンスMySQL 第3版", 5280), Book.create("978-4295000198", "やさしく学べるMySQL運用・管理入門【5.7対応】", 2860), Book.create("978-4798147406", "詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)", 3960), Book.create("978-4774170206", "MariaDB&MySQL全機能バイブル", 3860) ); bookIterator = books.iterator(); } @Override public Book read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } if (bookIterator.hasNext()) { return bookIterator.next(); } else { return null; } } }
10件の書籍データを扱うことにします。
ItemProcessor
。
src/main/java/org/littlewings/spring/batch/BookItemProcessor.java
package org.littlewings.spring.batch; import org.springframework.batch.item.ItemProcessor; public class BookItemProcessor implements ItemProcessor<Book, Book> { int currentCount = 0; @Override public Book process(Book item) throws Exception { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } return item; } }
ItemWriter
。
src/main/java/org/littlewings/spring/batch/BookItemWriter.java
package org.littlewings.spring.batch; import java.util.List; import javax.persistence.EntityManager; import org.springframework.batch.item.support.AbstractItemStreamItemWriter; import org.springframework.beans.factory.annotation.Autowired; public class BookItemWriter extends AbstractItemStreamItemWriter<Book> { @Autowired EntityManager entityManager; int currentCount = 0; @Override public void write(List<? extends Book> items) throws Exception { for (Book book : items) { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); } } }
ItemWriter
は、データ1件ずつフラッシュするようにしています。SQLをすぐに実行したいからですね。
いずれにも共通のパターンがありますが、7件目のデータを扱うところでコメントアウトを解除すると例外をスローするようになっています。
RuntimeException
およびException
です。
if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); }
ItemReader
、ItemProcessor
、ItemWriter
それぞれでこのコメントアウトの解除を変化させつつ、どのような動きをするかを見ていきます。
Job
の定義はこちら。
src/main/java/org/littlewings/spring/batch/ChunkJobConfig.java
package org.littlewings.spring.batch; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ChunkJobConfig { @Bean public Job chunkJob(JobBuilderFactory jobBuilderFactory) { return jobBuilderFactory .get("chunkJob") .incrementer(new RunIdIncrementer()) .start(chunkStep(null)) .build(); } @Bean public Step chunkStep(StepBuilderFactory stepBuilderFactory) { return stepBuilderFactory .get("chunkStep") .<Book, Book>chunk(3) .reader(bookItemReader()) .processor(bookItemProcessor()) .writer(bookItemWriter()) .build(); } @Bean @StepScope public BookItemReader bookItemReader() { return new BookItemReader(); } @Bean @StepScope public BookItemProcessor bookItemProcessor() { return new BookItemProcessor(); } @Bean @StepScope public BookItemWriter bookItemWriter() { return new BookItemWriter(); } }
チャンクサイズは3としています。つまり、コメントアウトを解除すると、3つ目のチャンクの処理中に例外がスローされることに
なりますね。
では、確認していきましょう。
確認は、ソースコードを変更しつつパッケージングして
$ mvn package
Job
を指定して実行することにします。
$ java -Dspring.batch.job.names=chunkJob -jar target/batch-transaction-0.0.1-SNAPSHOT.jar
正常に終了する場合
まずは、正常に終了する場合から。
実行時のログはこちら。
2022-05-27 01:22:22.882 INFO 20890 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:22:23.417 INFO 20890 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=1}] 2022-05-27 01:22:23.628 INFO 20890 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:22:23.629 DEBUG 20890 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=1 2022-05-27 01:22:23.944 DEBUG 20890 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:22:23.945 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:22:23.953 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=1, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:22:24.072 DEBUG 20890 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:22:24.073 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:22:24.076 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=1, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:22:24.343 DEBUG 20890 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:22:24.344 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:22:24.345 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=1, version=3, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=9, filterCount=0, writeCount=9 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=3, rollbackCount=0, exitDescription= 2022-05-27 01:22:24.510 DEBUG 20890 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: true 2022-05-27 01:22:24.510 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=1, written=1, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:22:24.512 DEBUG 20890 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=1, version=4, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=10, filterCount=0, writeCount=10 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=4, rollbackCount=0, exitDescription= 2022-05-27 01:22:24.576 DEBUG 20890 --- [ main] o.s.batch.core.step.AbstractStep : Step execution success: id=1 2022-05-27 01:22:24.580 INFO 20890 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 950ms 2022-05-27 01:22:24.698 DEBUG 20890 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=1, version=6, name=chunkStep, status=COMPLETED, exitStatus=COMPLETED, readCount=10, filterCount=0, writeCount=10 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=4, rollbackCount=0 2022-05-27 01:22:24.757 INFO 20890 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED] in 1s268ms
データはこうなりました。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4295000198 | やさしく学べるMySQL運用・管理入門【5.7対応】 | 2860 | | 978-4774170206 | MariaDB&MySQL全機能バイブル | 3860 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798147406 | 詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE) | 3960 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | | 978-4873116389 | 実践ハイパフォーマンスMySQL 第3版 | 5280 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 10 rows in set (0.00 sec)
ItemReaderが例外をスローする場合
次は、ItemReader
が例外をスローする場合です。
まずは、RuntimeException
をスローしてみます。
@Override public Book read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { currentCount++; if (currentCount > 7) { throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } if (bookIterator.hasNext()) { return bookIterator.next(); } else { return null; } }
ログ。
2022-05-27 01:23:27.851 INFO 21357 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:23:28.190 INFO 21357 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=2}] 2022-05-27 01:23:28.312 INFO 21357 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:23:28.312 DEBUG 21357 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=2 2022-05-27 01:23:28.531 DEBUG 21357 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:23:28.532 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:23:28.536 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=2, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:23:28.575 DEBUG 21357 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:23:28.575 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:23:28.577 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=2, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.b.c.step.item.SimpleChunkProvider : Oops!! : java.lang.RuntimeException 2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=1, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:23:28.612 DEBUG 21357 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:38) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:12) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader$$FastClassBySpringCGLIB$$29093ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemReader$$EnhancerBySpringCGLIB$$9a856c3.read(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:99) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:180) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:126) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:118) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:71) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:23:28.619 ERROR 21357 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step chunkStep in job chunkJob java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:38) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:12) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader$$FastClassBySpringCGLIB$$29093ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemReader$$EnhancerBySpringCGLIB$$9a856c3.read(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:99) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:180) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:126) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:118) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:71) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:23:28.625 INFO 21357 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 313ms 2022-05-27 01:23:28.658 DEBUG 21357 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=2, version=4, name=chunkStep, status=FAILED, exitStatus=FAILED, readCount=7, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=1 2022-05-27 01:23:28.693 INFO 21357 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=2}] and the following status: [FAILED] in 448ms
ロールバックを表すログが出力されています。ちなみに、DEBUGレベルですね。
2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.b.c.step.item.SimpleChunkProvider : Oops!! : java.lang.RuntimeException 2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=1, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:23:28.612 DEBUG 21357 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!!
データは、チャンク2つ分だけが入っていますね。3つ目のチャンクは入っていません。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 6 rows in set (0.01 sec)
今度は、Exception
をスローしてみます。
@Override public Book read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); throw new Exception("Oops!!"); } if (bookIterator.hasNext()) { return bookIterator.next(); } else { return null; } }
ログ。
2022-05-27 01:25:29.476 INFO 21604 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:25:29.829 INFO 21604 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=3}] 2022-05-27 01:25:29.931 INFO 21604 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:25:29.932 DEBUG 21604 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=3 2022-05-27 01:25:30.098 DEBUG 21604 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:25:30.098 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:25:30.101 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=3, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:25:30.145 DEBUG 21604 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:25:30.145 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:25:30.147 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=3, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:25:30.194 DEBUG 21604 --- [ main] o.s.b.c.step.item.SimpleChunkProvider : Oops!! : java.lang.Exception 2022-05-27 01:25:30.195 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=1, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:25:30.195 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Oops!! 2022-05-27 01:25:30.201 DEBUG 21604 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Oops!! at org.springframework.batch.repeat.support.RepeatTemplate.rethrow(RepeatTemplate.java:320) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:256) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:118) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:71) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:39) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:12) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader$$FastClassBySpringCGLIB$$29093ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemReader$$EnhancerBySpringCGLIB$$b4130ec4.read(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:99) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:180) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:126) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] ... 50 common frames omitted 2022-05-27 01:25:30.208 ERROR 21604 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step chunkStep in job chunkJob java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:39) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:12) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader$$FastClassBySpringCGLIB$$29093ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemReader$$EnhancerBySpringCGLIB$$b4130ec4.read(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:99) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:180) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:126) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:118) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:71) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:25:30.215 INFO 21604 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 283ms 2022-05-27 01:25:30.258 DEBUG 21604 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=3, version=4, name=chunkStep, status=FAILED, exitStatus=FAILED, readCount=7, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=1 2022-05-27 01:25:30.315 INFO 21604 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=3}] and the following status: [FAILED] in 412ms
ロールバックされたようです。
登録されたデータ数には、変化がありません。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 6 rows in set (0.00 sec)
ログに関しては、よくよく見るとスタックトレースが変わっています。
RuntimeException
の場合。
2022-05-27 01:23:28.607 DEBUG 21357 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:23:28.612 DEBUG 21357 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:38) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:12) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader$$FastClassBySpringCGLIB$$29093ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
Exception
の場合。
2022-05-27 01:25:30.195 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Oops!! 2022-05-27 01:25:30.201 DEBUG 21604 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Oops!! at org.springframework.batch.repeat.support.RepeatTemplate.rethrow(RepeatTemplate.java:320) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:256) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:118) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:71) ~[spring-batch-core-4.3.6.jar!/:4.3.6] 〜省略〜 Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:39) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader.read(BookItemReader.java:12) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemReader$$FastClassBySpringCGLIB$$29093ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
よく見ると、Exception
の方はネストした例外になっています。そしてRuntimeException
でロールバックしたことになっています。
2022-05-27 01:25:30.195 DEBUG 21604 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Oops!!
どうやら、ラップして再スローしているようですね。RepeatException
をスローしたことになっています。
2022-05-27 01:25:30.201 DEBUG 21604 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Oops!! at org.springframework.batch.repeat.support.RepeatTemplate.rethrow(RepeatTemplate.java:320) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6]
RuntimeException
をスローした時の方が、素直な動きですね。
結論としては、RuntimeException
でもException
でもロールバックすることがわかりました。
ItemReader
は、いったん元に戻します。
@Override public Book read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } if (bookIterator.hasNext()) { return bookIterator.next(); } else { return null; } }
ItemProcessorが例外をスローする場合
次は、ItemProcessor
に移りましょう。
RuntimeException
をスローしてみます。
@Override public Book process(Book item) throws Exception { currentCount++; if (currentCount > 7) { throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } return item; }
実行ログ。
2022-05-27 01:29:23.714 INFO 21982 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:29:24.011 INFO 21982 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=4}] 2022-05-27 01:29:24.163 INFO 21982 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:29:24.163 DEBUG 21982 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=4 2022-05-27 01:29:24.390 DEBUG 21982 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:29:24.390 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:29:24.393 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=4, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:29:24.429 DEBUG 21982 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:29:24.429 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:29:24.431 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=4, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:29:24.461 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:29:24.461 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:29:24.465 DEBUG 21982 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:13) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemProcessor$$EnhancerBySpringCGLIB$$acf7a11d.process(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:134) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:319) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:210) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:29:24.471 ERROR 21982 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step chunkStep in job chunkJob java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:13) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemProcessor$$EnhancerBySpringCGLIB$$acf7a11d.process(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:134) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:319) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:210) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:29:24.475 INFO 21982 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 312ms 2022-05-27 01:29:24.502 DEBUG 21982 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=4, version=4, name=chunkStep, status=FAILED, exitStatus=FAILED, readCount=9, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=1 2022-05-27 01:29:24.534 INFO 21982 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=4}] and the following status: [FAILED] in 466ms
こちらもロールバックしているようです。
2022-05-27 01:29:24.461 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:29:24.465 DEBUG 21982 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:13) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20]
データ。2つのチャンク分のデータまでが入っていますね。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 6 rows in set (0.00 sec)
Exception
をスローしてみます。
@Override public Book process(Book item) throws Exception { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); throw new Exception("Oops!!"); } return item; }
ログ。
2022-05-27 01:30:47.367 INFO 22148 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:30:47.672 INFO 22148 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=5}] 2022-05-27 01:30:47.815 INFO 22148 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:30:47.815 DEBUG 22148 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=5 2022-05-27 01:30:48.011 DEBUG 22148 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:30:48.011 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:30:48.014 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=5, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:30:48.049 DEBUG 22148 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:30:48.050 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:30:48.052 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=5, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:30:48.083 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:30:48.083 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:30:48.088 DEBUG 22148 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:14) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemProcessor$$EnhancerBySpringCGLIB$$acf7a11d.process(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:134) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:319) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:210) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] ... 46 common frames omitted 2022-05-27 01:30:48.094 ERROR 22148 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step chunkStep in job chunkJob java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:14) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemProcessor$$EnhancerBySpringCGLIB$$acf7a11d.process(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:134) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:319) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:210) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:30:48.100 INFO 22148 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 284ms 2022-05-27 01:30:48.154 DEBUG 22148 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=5, version=4, name=chunkStep, status=FAILED, exitStatus=FAILED, readCount=9, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=1 2022-05-27 01:30:48.205 INFO 22148 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=5}] and the following status: [FAILED] in 455ms
ロールバックされたようです。
データ。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 6 rows in set (0.00 sec)
両方ともロールバックしましたが、やっぱりスタックトレースが変わりましたね。
RuntimeException
の場合。
2022-05-27 01:29:24.461 DEBUG 21982 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:29:24.465 DEBUG 21982 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:13) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
Exception
の場合。
2022-05-27 01:30:48.083 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:30:48.088 DEBUG 22148 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] 〜省略〜 Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:14) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor.process(BookItemProcessor.java:5) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemProcessor$$FastClassBySpringCGLIB$$775ca5c7.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
ItemProcessor
の場合は、Exception
のメッセージが変わっており、Exception
によりロールバックしたことになっています。
2022-05-27 01:30:48.083 DEBUG 22148 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:30:48.088 DEBUG 22148 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6]
そして、UncheckedTransactionException
をスローしたことになっています。
ItemProcessor
が例外をする場合でも、RuntimeException
、Exception
の両方でロールバックすることがわかりました。
ItemProcessor
は、元に戻しておきます。
@Override public Book process(Book item) throws Exception { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } return item; }
ItemWriterが例外をスローする場合
チャンクの最後は、ItemWriter
です。
RuntimeException
をスローします。
@Override public void write(List<? extends Book> items) throws Exception { for (Book book : items) { currentCount++; if (currentCount > 7) { throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); } }
ログ。
2022-05-27 01:34:44.319 INFO 22497 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:34:44.666 INFO 22497 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=6}] 2022-05-27 01:34:44.782 INFO 22497 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:34:44.782 DEBUG 22497 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=6 2022-05-27 01:34:44.987 DEBUG 22497 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:34:44.988 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:34:44.991 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=6, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:34:45.031 DEBUG 22497 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:34:45.032 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:34:45.034 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=6, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:34:45.064 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:34:45.064 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:34:45.068 DEBUG 22497 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemWriter.write(BookItemWriter.java:22) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemWriter$$FastClassBySpringCGLIB$$bd3df5e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemWriter$$EnhancerBySpringCGLIB$$37836e73.write(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:193) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:159) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:294) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:34:45.113 ERROR 22497 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step chunkStep in job chunkJob java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemWriter.write(BookItemWriter.java:22) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemWriter$$FastClassBySpringCGLIB$$bd3df5e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemWriter$$EnhancerBySpringCGLIB$$37836e73.write(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:193) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:159) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:294) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:34:45.118 INFO 22497 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 334ms 2022-05-27 01:34:45.164 DEBUG 22497 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=6, version=4, name=chunkStep, status=FAILED, exitStatus=FAILED, readCount=9, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=1 2022-05-27 01:34:45.274 INFO 22497 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=6}] and the following status: [FAILED] in 470ms
ロールバックしています。
2022-05-27 01:34:45.064 DEBUG 22497 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:34:45.068 DEBUG 22497 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookItemWriter.write(BookItemWriter.java:22) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemWriter$$FastClassBySpringCGLIB$$bd3df5e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
データ。やはり、チャンク2つ分です。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 6 rows in set (0.00 sec)
Exception
をスローしてみます。
@Override public void write(List<? extends Book> items) throws Exception { for (Book book : items) { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); } }
ログ。
2022-05-27 01:36:02.283 INFO 22698 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:36:02.598 INFO 22698 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] launched with the following parameters: [{run.id=7}] 2022-05-27 01:36:02.715 INFO 22698 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [chunkStep] 2022-05-27 01:36:02.715 DEBUG 22698 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=7 2022-05-27 01:36:02.920 DEBUG 22698 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:36:02.920 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:36:02.923 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=7, version=1, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=3, filterCount=0, writeCount=3 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:36:02.958 DEBUG 22698 --- [ main] o.s.b.c.step.item.ChunkOrientedTasklet : Inputs not busy, ended: false 2022-05-27 01:36:02.958 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=3, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:36:02.960 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=7, version=2, name=chunkStep, status=STARTED, exitStatus=EXECUTING, readCount=6, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=0, exitDescription= 2022-05-27 01:36:02.990 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=3, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:36:02.990 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:36:02.995 DEBUG 22698 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemWriter.write(BookItemWriter.java:23) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemWriter$$FastClassBySpringCGLIB$$bd3df5e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemWriter$$EnhancerBySpringCGLIB$$e1ee2674.write(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:193) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:159) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:294) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] ... 46 common frames omitted 2022-05-27 01:36:03.011 ERROR 22698 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step chunkStep in job chunkJob java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookItemWriter.write(BookItemWriter.java:23) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookItemWriter$$FastClassBySpringCGLIB$$bd3df5e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookItemWriter$$EnhancerBySpringCGLIB$$e1ee2674.write(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:193) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:159) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:294) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:36:03.014 INFO 22698 --- [ main] o.s.batch.core.step.AbstractStep : Step: [chunkStep] executed in 299ms 2022-05-27 01:36:03.068 DEBUG 22698 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=7, version=4, name=chunkStep, status=FAILED, exitStatus=FAILED, readCount=9, filterCount=0, writeCount=6 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=2, rollbackCount=1 2022-05-27 01:36:03.102 INFO 22698 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=chunkJob]] completed with the following parameters: [{run.id=7}] and the following status: [FAILED] in 448ms
ロールバックしたようです。
データ。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 6 rows in set (0.00 sec)
ItemWriter
の場合は、ItemProcessor
と同様にException
としてロールバックしているようです。
2022-05-27 01:36:02.990 DEBUG 22698 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:36:02.995 DEBUG 22698 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] 〜省略〜
UncheckedTransactionException
にラップされているのも同じようですが。
これで、ItemWriter
の場合もスローされる例外がException
、RuntimeException
を問わずロールバックされることがわかりました。
ItemWriter
のソースコードは、元に戻しておきます。
@Override public void write(List<? extends Book> items) throws Exception { for (Book book : items) { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); } }
Tasklet
チャンクの次は、Tasklet
を見ていきます。
Tasklet
のソースコードは、こちら。
src/main/java/org/littlewings/spring/batch/BookTasklet.java
package org.littlewings.spring.batch; import java.util.List; import javax.persistence.EntityManager; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; public class BookTasklet implements Tasklet { @Autowired EntityManager entityManager; @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { List<Book> books = List.of( Book.create("978-4798142470", "Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発", 4400), Book.create("978-4774182179", "[改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ", 4180), Book.create("978-1492076988", "Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications", 6265), Book.create("978-1484237236", "The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud", 7361), Book.create("978-4798161488", "MySQL徹底入門 第4版 MySQL 8.0対応", 4180), Book.create("978-4797393118", "基礎からのMySQL 第3版 (基礎からシリーズ)", 6038), Book.create("978-4873116389", "実践ハイパフォーマンスMySQL 第3版", 5280), Book.create("978-4295000198", "やさしく学べるMySQL運用・管理入門【5.7対応】", 2860), Book.create("978-4798147406", "詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)", 3960), Book.create("978-4774170206", "MariaDB&MySQL全機能バイブル", 3860) ); int currentCount = 0; for (Book book : books) { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); } return RepeatStatus.FINISHED; } }
10件の書籍データを、1件ずつ反映します。
Tasklet
もチャンクの時と同様、7件目のデータを扱うところでコメントアウトを解除すると例外をスローするようになっています。
RuntimeException
およびException
です。
if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); }
こちらもこのコメントアウトの解除を変化させつつ、どのような動きをするかを見ていきます。
Job
の定義はこちら。
src/main/java/org/littlewings/spring/batch/TaskletJobConfig.java
package org.littlewings.spring.batch; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TaskletJobConfig { @Bean public Job taskletJob(JobBuilderFactory jobBuilderFactory) { return jobBuilderFactory .get("taskletJob") .incrementer(new RunIdIncrementer()) .start(taskletStep(null)) .build(); } @Bean public Step taskletStep(StepBuilderFactory stepBuilderFactory) { return stepBuilderFactory .get("taskletStep") .tasklet(bookTasklet()) .build(); } @Bean @StepScope public BookTasklet bookTasklet() { return new BookTasklet(); } }
確認は、チャンクと同じようにソースコードを変更しつつパッケージングして
$ mvn package
Job
を指定して実行することにします。
$ java -Dspring.batch.job.names=taskletJob -jar target/batch-transaction-0.0.1-SNAPSHOT.jar
正常に終了する場合
まずは、正常に終了する場合から。
実行時のログは、こちら。
2022-05-27 01:37:47.923 INFO 22877 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:37:48.192 INFO 22877 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=taskletJob]] launched with the following parameters: [{run.id=1}] 2022-05-27 01:37:48.373 INFO 22877 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [taskletStep] 2022-05-27 01:37:48.373 DEBUG 22877 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=8 2022-05-27 01:37:48.543 DEBUG 22877 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:37:48.546 DEBUG 22877 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Saving step execution before commit: StepExecution: id=8, version=1, name=taskletStep, status=STARTED, exitStatus=EXECUTING, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= 2022-05-27 01:37:48.573 DEBUG 22877 --- [ main] o.s.batch.core.step.AbstractStep : Step execution success: id=8 2022-05-27 01:37:48.582 INFO 22877 --- [ main] o.s.batch.core.step.AbstractStep : Step: [taskletStep] executed in 208ms 2022-05-27 01:37:48.609 DEBUG 22877 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=8, version=3, name=taskletStep, status=COMPLETED, exitStatus=COMPLETED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0 2022-05-27 01:37:48.637 INFO 22877 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=taskletJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED] in 390ms
データ。
mysql> select * from book; +----------------+---------------------------------------------------------------------------------------------------------+-------+ | isbn | title | price | +----------------+---------------------------------------------------------------------------------------------------------+-------+ | 978-1484237236 | The Definitive Guide to Spring Batch: Modern Finite Batch Processing in the Cloud | 7361 | | 978-1492076988 | Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications | 6265 | | 978-4295000198 | やさしく学べるMySQL運用・管理入門【5.7対応】 | 2860 | | 978-4774170206 | MariaDB&MySQL全機能バイブル | 3860 | | 978-4774182179 | [改訂新版]Spring入門 ――Javaフレームワーク・より良い設計とアーキテクチャ | 4180 | | 978-4797393118 | 基礎からのMySQL 第3版 (基礎からシリーズ) | 6038 | | 978-4798142470 | Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 | 4400 | | 978-4798147406 | 詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE) | 3960 | | 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応 | 4180 | | 978-4873116389 | 実践ハイパフォーマンスMySQL 第3版 | 5280 | +----------------+---------------------------------------------------------------------------------------------------------+-------+ 10 rows in set (0.00 sec)
Taskletが例外をスローする場合
では、例外をスローするようにして動作確認してみます。
まずはRuntimeException
をスローしてみます。
for (Book book : books) { currentCount++; if (currentCount > 7) { throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); }
ログ。
2022-05-27 01:39:52.695 INFO 23081 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:39:53.006 INFO 23081 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=taskletJob]] launched with the following parameters: [{run.id=2}] 2022-05-27 01:39:53.140 INFO 23081 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [taskletStep] 2022-05-27 01:39:53.140 DEBUG 23081 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=9 2022-05-27 01:39:53.320 DEBUG 23081 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:39:53.320 DEBUG 23081 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:39:53.326 DEBUG 23081 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:37) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookTasklet$$EnhancerBySpringCGLIB$$54aa2694.execute(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:39:53.363 ERROR 23081 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step taskletStep in job taskletJob java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:37) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookTasklet$$EnhancerBySpringCGLIB$$54aa2694.execute(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:39:53.369 INFO 23081 --- [ main] o.s.batch.core.step.AbstractStep : Step: [taskletStep] executed in 229ms 2022-05-27 01:39:53.410 DEBUG 23081 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=9, version=2, name=taskletStep, status=FAILED, exitStatus=FAILED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=0, rollbackCount=1 2022-05-27 01:39:53.441 INFO 23081 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=taskletJob]] completed with the following parameters: [{run.id=2}] and the following status: [FAILED] in 384ms
ロールバックしています。
2022-05-27 01:39:53.320 DEBUG 23081 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:39:53.326 DEBUG 23081 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:37) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] 〜省略〜
Tasklet
の場合はトランザクションはひとつなので、すべてのデータがロールバックしましたね。
mysql> select * from book; Empty set (0.00 sec)
Exception
をスローしてみます。
for (Book book : books) { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); }
ログ。
2022-05-27 01:41:41.628 INFO 23266 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2022-05-27 01:41:41.962 INFO 23266 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=taskletJob]] launched with the following parameters: [{run.id=3}] 2022-05-27 01:41:42.092 INFO 23266 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [taskletStep] 2022-05-27 01:41:42.093 DEBUG 23266 --- [ main] o.s.batch.core.step.AbstractStep : Executing: id=10 2022-05-27 01:41:42.254 DEBUG 23266 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Applying contribution: [StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 2022-05-27 01:41:42.255 DEBUG 23266 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:41:42.260 DEBUG 23266 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:38) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookTasklet$$EnhancerBySpringCGLIB$$54aa2694.execute(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] ... 46 common frames omitted 2022-05-27 01:41:42.288 ERROR 23266 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step taskletStep in job taskletJob java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:38) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.littlewings.spring.batch.BookTasklet$$EnhancerBySpringCGLIB$$54aa2694.execute(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:413) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.20.jar!/:5.3.20] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.20.jar!/:5.3.20] at jdk.proxy2/jdk.proxy2.$Proxy83.run(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150) ~[spring-boot-autoconfigure-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar!/:2.7.0] at org.littlewings.spring.batch.App.main(App.java:11) ~[classes!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[batch-transaction-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] 2022-05-27 01:41:42.297 INFO 23266 --- [ main] o.s.batch.core.step.AbstractStep : Step: [taskletStep] executed in 203ms 2022-05-27 01:41:42.362 DEBUG 23266 --- [ main] o.s.batch.core.step.AbstractStep : Step execution complete: StepExecution: id=10, version=2, name=taskletStep, status=FAILED, exitStatus=FAILED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=0, rollbackCount=1 2022-05-27 01:41:42.411 INFO 23266 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=taskletJob]] completed with the following parameters: [{run.id=3}] and the following status: [FAILED] in 377ms
ロールバックしました。
2022-05-27 01:41:42.260 DEBUG 23266 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] 〜省略〜
チャンクの時と同じように、UncheckedTransactionException
にラップされてスローされていますね。ロールバックの理由については
Exception
として扱っていますが。
データもロールバックされています。
mysql> select * from book; Empty set (0.00 sec)
RuntimeException
とException
のスタックトレースをちょっと比較。
RuntimeException
。
2022-05-27 01:39:53.320 DEBUG 23081 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for RuntimeException: java.lang.RuntimeException: Oops!! 2022-05-27 01:39:53.326 DEBUG 23081 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception java.lang.RuntimeException: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:37) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
Exception
。
2022-05-27 01:41:42.255 DEBUG 23266 --- [ main] o.s.batch.core.step.tasklet.TaskletStep : Rollback for Exception: java.lang.Exception: Oops!! 2022-05-27 01:41:42.260 DEBUG 23266 --- [ main] o.s.t.support.TransactionTemplate : Initiating transaction rollback on application exception org.springframework.batch.core.step.tasklet.UncheckedTransactionException: java.lang.Exception: Oops!! at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:487) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.20.jar!/:5.3.20] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.6.jar!/:4.3.6] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.6.jar!/:4.3.6] 〜省略〜 Caused by: java.lang.Exception: Oops!! at org.littlewings.spring.batch.BookTasklet.execute(BookTasklet.java:38) ~[classes!/:0.0.1-SNAPSHOT] at org.littlewings.spring.batch.BookTasklet$$FastClassBySpringCGLIB$$1150977e.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar!/:5.3.20] 〜省略〜
これで、Tasklet
の場合もスローされる例外がRuntimeException
であってもException
であってもロールバックされることがわかりましたね。
ソースコードは、元に戻しておきます。
for (Book book : books) { currentCount++; if (currentCount > 7) { // throw new RuntimeException("Oops!!"); // throw new Exception("Oops!!"); } entityManager.persist(book); entityManager.flush(); }
少し追ってみる
ここまで見てきて、各要素からException
がスローされた場合は、RepeatException
またはUncheckedTransactionException
にラップされて
再度スローされることがわかりました。
また、この時のItemProcessor
、ItemWriter
、Tasklet
のスタックトレースはすべて同じであり、ラップされる例外も
UncheckedTransactionException
です。ItemReader
だけ異なり、ラップされる例外はRepeatException
ですね。
ここで少し、Spring Batchの実装を見てみましょう。
ItemReader
で例外を扱っていた(再スローしていた)のは、こちらでした。
Error
、RuntimeException
、Exception
それぞれを見ています。Exception
の場合は、RepeatException
という例外でラップして
再スローですね。
ItemProcessor
、ItemWriter
、Tasklet
の場合はこちら。
Error
、RuntimeException
、Exception
それぞれを見ています。Exception
の場合は、UncheckedTransactionException
という
例外にラップされてスローされます。
そして、いずれの構成要素であっても、RuntimeException
、Exception
問わず、例外がスローされたらロールバックされることが
確認できました、と。
まとめ
Spring Batchのトランザクション管理で、スローされる例外がRuntimeException
、Exception
に関わらずロールバックされることを
確認してみました。
なんとなくException
でもロールバックするのだろうと思っていましたが、実際に確認しておくと安心かなと。
Exception
の場合は、内部的には別の例外でラップされて再スローされていることもわかりましたし。