Coder Social home page Coder Social logo

spring-guides / gs-batch-processing Goto Github PK

View Code? Open in Web Editor NEW
231.0 35.0 414.0 1.21 MB

Creating a Batch Service :: Learn how to create a basic batch-driven solution.

Home Page: https://spring.io/guides/gs/batch-processing/

License: Apache License 2.0

Java 100.00%
spring-batch

gs-batch-processing's Introduction

This guide walks you through the process of creating a basic batch-driven solution.

What You Will build

You will build a service that imports data from a CSV spreadsheet, transforms it with custom code, and stores the final results in a database.

Starting with Spring Initializr

You can use this pre-initialized project and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.

To manually initialize the project:

  1. Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.

  2. Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.

  3. Click Dependencies and select Spring Batch and HyperSQL Database.

  4. Click Generate.

  5. Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.

Note
If your IDE has the Spring Initializr integration, you can complete this process from your IDE.
Note
You can also fork the project from Github and open it in your IDE or other editor.

Business Data

Typically, your customer or a business analyst supplies a spreadsheet. For this simple example, you can find some made-up data in src/main/resources/sample-data.csv:

link:initial/src/main/resources/sample-data.csv[role=include]

This spreadsheet contains a first name and a last name on each row, separated by a comma. This is a fairly common pattern that Spring can handle without customization.

Next, you need to write an SQL script to create a table to store the data. You can find such a script in src/main/resources/schema-all.sql:

link:initial/src/main/resources/schema-all.sql[role=include]
Note
Spring Boot runs schema-@@platform@@.sql automatically during startup. -all is the default for all platforms.

Create a Business Class

Now that you can see the format of data inputs and outputs, you can write code to represent a row of data, as the following example (from src/main/java/com/example/batchprocessing/Person.java) shows:

link:complete/src/main/java/com/example/batchprocessing/Person.java[role=include]

You can instantiate the Person record with first name and last name through the constructor.

Create an Intermediate Processor

A common paradigm in batch processing is to ingest data, transform it, and then pipe it out somewhere else. Here, you need to write a simple transformer that converts the names to uppercase. The following listing (from src/main/java/com/example/batchprocessing/PersonItemProcessor.java) shows how to do so:

link:complete/src/main/java/com/example/batchprocessing/PersonItemProcessor.java[role=include]

PersonItemProcessor implements Spring Batch’s ItemProcessor interface. This makes it easy to wire the code into a batch job that you will define later in this guide. According to the interface, you receive an incoming Person object, after which you transform it to an upper-cased Person.

Note
The input and output types need not be the same. In fact, after one source of data is read, sometimes the application’s data flow needs a different data type.

Put Together a Batch Job

Now you need to put together the actual batch job. Spring Batch provides many utility classes that reduce the need to write custom code. Instead, you can focus on the business logic.

To configure your job, you must first create a Spring @Configuration class like the following example in src/main/java/com/example/batchprocessing/BatchConfiguration.java. This example uses a memory-based database, meaning that, when it is done, the data is gone. Now add the following beans to your BatchConfiguration class to define a reader, a processor, and a writer:

link:complete/src/main/java/com/example/batchprocessing/BatchConfiguration.java[role=include]

The first chunk of code defines the input, processor, and output.

  • reader() creates an ItemReader. It looks for a file called sample-data.csv and parses each line item with enough information to turn it into a Person.

  • processor() creates an instance of the PersonItemProcessor that you defined earlier, meant to convert the data to upper case.

  • writer(DataSource) creates an ItemWriter. This one is aimed at a JDBC destination and automatically gets a copy of the dataSource created by Spring Boot. It includes the SQL statement needed to insert a single Person, driven by Java record components.

The last chunk (from src/main/java/com/example/batchprocessing/BatchConfiguration.java) shows the actual job configuration:

link:complete/src/main/java/com/example/batchprocessing/BatchConfiguration.java[role=include]

The first method defines the job, and the second one defines a single step. Jobs are built from steps, where each step can involve a reader, a processor, and a writer.

You then list each step, (though this job has only one step). The job ends, and the Java API produces a perfectly configured job.

In the step definition, you define how much data to write at a time. In this case, it writes up to three records at a time. Next, you configure the reader, processor, and writer by using the beans injected earlier.

Note
chunk() is prefixed <Person,Person> because it is a generic method. This represents the input and output types of each “chunk” of processing and lines up with ItemReader<Person> and ItemWriter<Person>.

The last bit of batch configuration is a way to get notified when the job completes. The following example (from src/main/java/com/example/batchprocessing/JobCompletionNotificationListener.java) shows such a class:

link:complete/src/main/java/com/example/batchprocessing/JobCompletionNotificationListener.java[role=include]

The JobCompletionNotificationListener listens for when a job is BatchStatus.COMPLETED and then uses JdbcTemplate to inspect the results.

Make the Application Executable

Although batch processing can be embedded in web apps and WAR files, the simpler approach demonstrated below creates a standalone application. You package everything in a single, executable JAR file, driven by a good old Java main() method.

The Spring Initializr created an application class for you. For this simple example, it works without further modification. The following listing (from src/main/java/com/example/batchprocessing/BatchProcessingApplication.java) shows the application class:

link:complete/src/main/java/com/example/batchprocessing/BatchProcessingApplication.java[role=include]

Note that SpringApplication.exit() and System.exit() ensure that the JVM exits upon job completion. See the Application Exit section in Spring Boot Reference documentation for more details.

For demonstration purposes, there is code to create a JdbcTemplate, query the database, and print out the names of people the batch job inserts.

Note

Note how the application does not use the @EnableBatchProcessing annotation. Previously, @EnableBatchProcessing could be used to enable Spring Boot’s auto-configuration of Spring Batch. Starting from Spring Boot v3.0, this annotation is no longer required and should be removed from applications that want to use Spring Boot’s auto-configuration. A bean that is annotated with @EnableBatchProcessing or that extends Spring Batch’s DefaultBatchConfiguration can now be defined to tell the auto-configuration to back off, allowing the application to take complete control of how Spring Batch is configured.

The job prints out a line for each person that gets transformed. After the job runs, you can also see the output from querying the database. It should resemble the following output:

Converting (Person[firstName=Jill, lastName=Doe]) into (Person[firstName=JILL, lastName=DOE])
Converting (Person[firstName=Joe, lastName=Doe]) into (Person[firstName=JOE, lastName=DOE])
Converting (Person[firstName=Justin, lastName=Doe]) into (Person[firstName=JUSTIN, lastName=DOE])
Converting (Person[firstName=Jane, lastName=Doe]) into (Person[firstName=JANE, lastName=DOE])
Converting (Person[firstName=John, lastName=Doe]) into (Person[firstName=JOHN, lastName=DOE])
Found <{Person[firstName=JILL, lastName=DOE]}> in the database.
Found <{Person[firstName=JOE, lastName=DOE]}> in the database.
Found <{Person[firstName=JUSTIN, lastName=DOE]}> in the database.
Found <{Person[firstName=JANE, lastName=DOE]}> in the database.
Found <{Person[firstName=JOHN, lastName=DOE]}> in the database.

Summary

Congratulations! You built a batch job that ingested data from a spreadsheet, processed it, and wrote it to a database.

gs-batch-processing's People

Contributors

bclozel avatar btalbott avatar buzzardo avatar cbeams avatar dependabot[bot] avatar doobrie avatar dsyer avatar fmbenhassine avatar gregturn avatar habuma avatar izeye avatar mandroide avatar mminella avatar nabetama avatar psoares avatar robertmcnees avatar royclarkson avatar sdeleuze avatar sebm avatar spring-operator avatar vilisimo avatar xavierkress avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gs-batch-processing's Issues

Is it possible to integrate spring batch admin into this demo?

I'm evaluating spring boot for a batch project and I'd like to integrate also batch admin ui. I used this project as proof of concept to develop basic functionalities but I'm not able to integrate the admin ui. Is it possible? Any hint on how to do that?

Java 11 doesn't work..!

Two days ago I completed this guide with Java 11 version.
But I retried it today but It didn't work.
There are compile error:
[class file has wrong version 61.0, should be 55.0 ]

Is it only can tested by Java 17?

AS-IS my pom.xml file:

org.springframework.boot
spring-boot-starter-parent
2.7.6

TOBE :

org.springframework.boot
spring-boot-starter-parent
3.0.0

if I change version
JobBuilder class and StepBuilder class are having more constructor.

return new JobBuilder("importUserJob", jobRepository)
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step1)
.end()
.build();

So this code cannot be resolved!
because when I use 2.7.6 version JobBuilder class has only one constructor

public JobBuilder(String name) {
super(name);
}

How can I resolve this problem?

Adding my own JobParameters - How to replace/intercept the 'jobLauncher.run(...)' method?

Hi,
I'm new to Spring batch but your great tutorial is allowing me to explore the JobExplorer APIs for finished Job instances (excuse the pun).

My question is, how can I add my own JobParameters to the JobLauncher.run(...) invocation of the "importUserJob" Job bean?

I'm not entirely sure how to override the job's execution, your 'jobLauncher.run(...)' call is a little bit 'hidden' within your Spring-derived dependency library, at 'JobLauncherCommandLineRunner.execute()', within 'spring-boot-autoconfigure-1.5.2.RELEASE.jar'.

Am I right in assuming that, just having the bean references to the Job/JobLauncher, in BatchConfiguration.java, isn't enough for me to add my own parameters to that job? Do I need to just, explicitly, execute my own Job instances via JobLauncher.run(...), where I can also supply my own 'JobParameters' instance?

The 'JobExecutionListenerSupport.beforeJob(JobExecution)' method is actually called too 'late', as, a Job instanced has already been started, and passed an immutable JobParameter object, at that time.

Unnecessary Asciidoctor tags in code samples

I was wondering what these "tags" in your code samples are about:

Took me a while to find out these are artifacts of your AsciiDoc markup. Since in the tutorial you include the source code file as a whole, the tags are also included. That way they are useless, but visible. And funnily, your tags have been copied all over the Internet :-D

Maybe you can remove these AsciiDoc tags from the source?

Maven build fails to produce viable jar

Hi,

When using maven to build the complete/ sub-project, the jar produced cannot be used in a standalone way. The gradlew build path does create a suitable jar.

Steps to reproduce:

Expected output:

Similar to the gradlew output, an ascii art "SPRING" banner, some logging and then, intermixed with the logging:

Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)
Converting (firstName: Joe, lastName: Doe) into (firstName: JOE, lastName: DOE)
Converting (firstName: Justin, lastName: Doe) into (firstName: JUSTIN, lastName: DOE)
Converting (firstName: Jane, lastName: Doe) into (firstName: JANE, lastName: DOE)
Converting (firstName: John, lastName: Doe) into (firstName: JOHN, lastName: DOE)
Found <firstName: JILL, lastName: DOE> in the database.
Found <firstName: JOE, lastName: DOE> in the database.
Found <firstName: JUSTIN, lastName: DOE> in the database.
Found <firstName: JANE, lastName: DOE> in the database.
Found <firstName: JOHN, lastName: DOE> in the database.

Actual Output:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2482)
        at java.lang.Class.getDeclaredMethod(Class.java:1982)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at java.lang.Thread.run(Thread.java:679)
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
        at org.springframework.boot.loader.LaunchedURLClassLoader.findClass(LaunchedURLClassLoader.java:110)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
        at org.springframework.boot.loader.LaunchedURLClassLoader.doLoadClass(LaunchedURLClassLoader.java:93)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:65)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
        ... 5 more

Branch:

master, commit hash: 6915a41

Versions:

  • Java:
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1~deb6u1)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)
  • Maven:
Apache Maven 2.2.1 (rdebian-4)
Java version: 1.6.0_26
Java home: /usr/lib/jvm/java-6-sun-1.6.0.26/jre
Default locale: en_GB, platform encoding: UTF-8
OS name: "linux" version: "2.6.32-5-amd64" arch: "amd64" Family: "unix"

Existing work-arounds:

Just use gradlew for the moment.

Other notes:

I've had a quick play around with gs-spring-boot today as well, and that project also displayed similar behaviour, though I did not test that the gradlew workaround works.

Guide without Spring Boot

This is just a suggestion to improve the documentation, partly related to spring-guides/getting-started-guides#9.

It would be great to explain what happens in this code:

@SpringBootApplication
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

I understand the main reason to have Getting Started guides mostly based around Spring Boot is to avoid having to re-explain data sources and so on, but I'm talking about what's specific to Spring Batch: more specifically, how to make the jobs actually run.

Thankfully, I've found this external article: http://malsolo.com/blog4java/?p=260

I've been able to adapt it to my examples like so:

@Component
public class HelloApplication {
    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private Job importUserJob;

    @Autowired
    public static void main(String[] args) throws Exception {
        try (AnnotationConfigApplicationContext springContext = new AnnotationConfigApplicationContext(
                ConfigBean.class)) {
            HelloApplication main = springContext
                    .getBean(HelloApplication.class);

            main.jobLauncher.run(main.importUserJob,
                    new JobParameters());
        }
    }
}

It would be great to elaborate a bit more in the guides about where the JobLauncher.run(...) is implied, and under which circumstances certain things will be configured or called.

What can often be tricky is to distinguish between what's automatically picked up by non-Boot Spring (e.g. regular @ComponentScan) and may need to be explicitly enabled or disabled, and what's automatically done because of Spring Boot.

Update Spring Boot to the Latest Version

Update the guide to use the most recent Spring Boot version.

Files that require changes are:

initial/build.gradle
initial/pom.xml
complete/build.gradle
complete/pom.xml

HSQLException : user lacks privilege or object not found BATCH_JOB_INSTANCE

I am getting this error while running the jar, even as admin

2018-02-28 13:27:22.371 ERROR 7460 --- [ main] o.s.boot.SpringApplication : Application startup failed java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:735) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at hello.Application.main(Application.java:10) [classes!/:0.1.0] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [gs-batch-processing-0.1.0.jar:0.1.0] at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [gs-batch-processing-0.1.0.jar:0.1.0] at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [gs-batch-processing-0.1.0.jar:0.1.0] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [gs-batch-processing-0.1.0.jar:0.1.0] Caused by: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? order by JOB_INSTANCE_ID desc]; nested exception is java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: BATCH_JOB_INSTANCE in statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? order by JOB_INSTANCE_ID desc] at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:91) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:655) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:690) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:722) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:732) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.getJobInstances(JdbcJobInstanceDao.java:230) ~[spring-batch-core-3.0.8.RELEASE.jar!/:3.0.8.RELEASE] at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobInstances(SimpleJobExplorer.java:173) ~[spring-batch-core-3.0.8.RELEASE.jar!/:3.0.8.RELEASE] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) ~[spring-aop-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) ~[spring-batch-core-3.0.8.RELEASE.jar!/:3.0.8.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at com.sun.proxy.$Proxy46.getJobInstances(Unknown Source) ~[na:na] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.getNextJobParameters(JobLauncherCommandLineRunner.java:131) ~[spring-boot-autoconfigure-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:210) ~[spring-boot-autoconfigure-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:227) ~[spring-boot-autoconfigure-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:123) ~[spring-boot-autoconfigure-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:117) ~[spring-boot-autoconfigure-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.10.RELEASE.jar!/:1.5.10.RELEASE] ... 14 common frames omitted Caused by: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: BATCH_JOB_INSTANCE in statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? order by JOB_INSTANCE_ID desc] at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.jdbc.JDBCPreparedStatement.<init>(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.jdbc.JDBCConnection.prepareStatement(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na] at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126) ~[tomcat-jdbc-8.5.27.jar!/:na] at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.27.jar!/:na] at org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:75) ~[tomcat-jdbc-8.5.27.jar!/:na] at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.27.jar!/:na] at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81) ~[tomcat-jdbc-8.5.27.jar!/:na] at com.sun.proxy.$Proxy53.prepareStatement(Unknown Source) ~[na:na] at org.springframework.jdbc.core.JdbcTemplate$SimplePreparedStatementCreator.createPreparedStatement(JdbcTemplate.java:1530) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633) ~[spring-jdbc-4.3.14.RELEASE.jar!/:4.3.14.RELEASE] ... 36 common frames omitted Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: BATCH_JOB_INSTANCE at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.readTableName(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.readTableOrSubquery(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadTableReference(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadFromClause(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadTableExpression(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadQuerySpecification(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadSimpleTable(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadQueryPrimary(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadQueryTerm(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadQueryExpressionBody(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.XreadQueryExpression(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserDQL.compileCursorSpecification(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserCommand.compilePart(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.ParserCommand.compileStatement(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.Session.compileStatement(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.StatementManager.compile(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] at org.hsqldb.Session.execute(Unknown Source) ~[hsqldb-2.3.5.jar!/:2.3.5] ... 50 common frames omitted

Update Spring Boot to latest version

Update the guide to use the most recent Spring Boot version.

Files that require changes are:
initial/build.gradle
initial/pom.xml
complete/build.gradle
complete/pom.xml

When running the tutorial, SELECT from the database happens before INSERT

Hi there,

I'm brand new to Spring Batch, so I was following the tutorial at https://spring.io/guides/gs/batch-processing/ and it made sense for the most part. However, when I got to the point of actually running the code, I noticed that I was only seeing the output for when the data was processed, e.g.

Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)

but not for when the data was read from the internal database, e.g.

Found <firstName: JILL, lastName: DOE> in the database.

This occurred regardless of whether I used "gradlew bootRun" or "gradlew build" followed by "java -jar build/libs/gs-batch-processing-0.1.0.jar." After adding in some debug statements, it appeared to me that the SELECT statement in Application.run() was getting called before the INSERT statements of BatchConfiguration.writer().

Do you have any suggestions for why this is happening?

In case it matters, I'm using Java version 1.8.0_20 on Windows 7 64-bit.

Thank you for any help you can provide!
David

no scope "step" available

Hi,

I tried to little bit enhance your nice example with the possibility to set the CSV file location from outside (instead of using the classpath).

If I modify the code from the ItemReader to

@Bean
  @Scope("step")
  public ItemReader<Person> reader() {

and then running the commandline (without any further changes!) I get following error:

    ... 37 more
Caused by: java.lang.IllegalStateException: No context holder available for step scope
        at org.springframework.batch.core.scope.StepScope.getContext(StepScope.java:160)
        at org.springframework.batch.core.scope.StepScope.get(StepScope.java:99)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:338)
        ... 43 more

From the Spring documentation, the scope should be available (because of the Batch annotation).

Do you have any hint/idea whats the problem?

Example of skip policy configuration in this example

I used this example as a reference for a quick (and successful) implementation of Spring batch in a Spring boot application. The doc/reference mainly shows skip policy configuration in XML, where would be the proper placement for skipping records within the sample? Thanks for your time.

Add clarification about s1 argument in importUserJob

Looking at the example, I can't figure out how the importUserJob can just declare an argument of type Step and know to pull in the value of the step1 bean. I can only assume it knows to do that because there's only one Step-typed bean defined, which leads me to wonder what I'd need to do if I wanted two steps defined for a job, or if I had two jobs defined each with one step.

Do you think it would be valuable to add information about how to ensure steps are going into the right job? I know it's not directly applicable to this example, but it may merit either making the example slightly more complicated to include another step. Alternatively, and a potential better approach, may be to use a way of defining steps for jobs in a less opaque way (directly calling the method, for example). Or maybe keep the example the same but explain what's going on?

I'm far from an expert on this, so there might be something obvious that I'm missing.

Gradle build for the complete project is broken

A typo in the gradle.build prevents the project from compiling.
mvn install fails with the following error:

Plugin [id: 'org.springframework.boot', version: '3,0.0'] was not found in any of the following sources:

The coma in 3,0.0 needs to be replaced by a dot and become 3.0.0 (or 3.0.2 at this time).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.