Closed9
Spring Batch 開発メモ
ピン留めされたアイテム
Spring Batchでバッチを書いていて、躓いた点などをメモしています。
エラー
ライブラリのDependencyで NoSuchBeanDefinitionException
エラーが発生する。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'scopedTarget.sampleReader': Unsatisfied dependency expressed through field 'sampleRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.library.sampleRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
解決策
@ComponentScan
で読み込む
@SpringBootApplication
@ComponentScan({"com.example.library"})
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
他にもいくつかBeanを読み込む方法がある。上記の方法は、パッケージを一括で取り込む方法。
エラー
BATCH_JOB_INSTANCE
テーブルが存在しないのが原因でエラーになる
Caused by: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?]; nested exception is java.sql.SQLSyntaxErrorException: (conn=266415) Table 'main.BATCH_JOB_INSTANCE' doesn't exist
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:239) ~[spring-jdbc-5.3.18.jar:5.3.18]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) ~[spring-jdbc-5.3.18.jar:5.3.18]
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1541) ~[spring-jdbc-5.3.18.jar:5.3.18]
...
解決策
- 接続しているデータベースにSchemaを追加する
- Dependencyの中から
org.springframework.batch:spring-batch-core:4.x.x
を探す - ->
spring-batch-core-4.x.x.jar
>org.springframework.batch.core
> 中にschema定義のSQLがある(例:schema-mysql.sql
)。これをデータベース上で実行させれば良い。
- Dependencyの中から
-
spring.batch.jdbc.initialize-schema = ALWAYS
を使う(動作未確認)
エラー
Spring BatchでJPAを利用していて、CannotCreateTransactionException
が発生する
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@2ef63b6d] for key [HikariDataSource (HikariPool-1)] bound to thread
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:467) ~[spring-orm-5.3.18.jar:5.3.18]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400) ~[spring-tx-5.3.18.jar:5.3.18]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) ~[spring-tx-5.3.18.jar:5.3.18]
...
解決策
(プロジェクトの既存設定によって解決方法が結構違うかも)
-
JpaTransactionManager
のBeanを@Configuration
が付いているConfigクラスに追加する
@Bean
public JpaTransactionManager jpaTransactionManager() {
return new JpaTransactionManager();
}
- (Chunkを利用する場合)Step の中に
transactionManager
を入れる
@Bean
public Step chunkStep() {
return stepBuilderFactory.get("ChunkStep")
.<String, String>chunk(CHUNK_COUNT)
.reader(itemReader)
.processor(itemProcessor)
.writer(itemWriter)
.transactionManager(jpaTransactionManager())
.build();
}
その他の解決方法:
パラメーターを受け取る方法
以下を定義する。
@Value("#{jobParameters['key']}")
@StepScope
@JobScope
が付いているBeanでjobParameters
を指定することが可能。
@BeforeStep
を利用して引数を受け取る方法もある。
application.yml
から任意の値を取得する
-
application.yml
に任意の値を追加したあとに、org.springframework.beans.factory.annotation
package内にある@Value
を利用すれば良い。
application.yml
example:
value: xyz
@Value("${example:value}")
private String input;
参考
JPQL関連エラー
(Spring Batchには関連無いが…)
コード
@Query("SELECT date, sum(amount) FROM my_table GROUP BY date")
List<PartnerDaily> getPartnerSummary(LocalDate date);
エラー内容
...
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException:
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:170)
at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:91)
...
対応方法
- 自分の場合はテーブルの指定方法が間違えていた。
my_table
というテーブルだと、JPQLではMyTable
と書く必要があった。
JPQL関連エラー その2
コード
Repository.java
// 本当は複雑なクエリを書く予定だが、デバッグのために単純化
@Query("SELECT path.to.package.Data(amount) FROM my_table")
List<PartnerDaily> getData(LocalDate date);
path.to.package.Data.java
@Getter
@Setter
public class Data {
private Integer amount;
}
エラー内容
- 長いエラーだったが、最後に以下のようなエラーがある
.....(略)
Caused by: org.hibernate.QueryException: No data type for node: org.hibernate.hql.internal.ast.tree.MethodNode
\-[METHOD_CALL] MethodNode: '('
+-[METHOD_NAME] IdentNode: 'path.to.package.Data' {originalText=path.to.package.MyTable}
\-[EXPR_LIST] SqlNode: 'exprList'
\-[DOT] DotNode:
.....(略)
解消方法
-
new
がJPQL内から抜けていた。以下のコードに修正する。
Repository.java
// 本当は複雑なクエリを書く予定だが、デバッグのために単純化
@Query("SELECT new path.to.package.Data(amount) FROM my_table")
List<PartnerDaily> getData(LocalDate date);
- しかし、さらにエラーが発生する。
.....(略)
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [.....(略)
-
Data
クラスにコンストラクターが不足しており、追加する必要があった- Lombokを利用している場合は
@AllArgsConstructor
を追加すれば良い。
- Lombokを利用している場合は
参考
- この記事を最初からきちんと読んでいれば、上記のエラーにハマる必要は無かった。。
このスクラップは2023/02/02にクローズされました