{"id":485192,"date":"2026-06-26T14:33:31","date_gmt":"2026-06-26T14:33:31","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=485192"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=485192","title":{"rendered":"Spring Batch \u043d\u0430\u0443\u0447\u0438\u043b\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 MongoDB"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Spring Batch \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0437\u0430 \u043c\u043d\u043e\u0433\u043e \u043b\u0435\u0442 \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f MongoDB, \u0438 \u0435\u0433\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u043b\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 SQL-\u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u0439 Spring Batch.<\/p>\n<p>\u041d\u043e \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0434\u0435\u0441\u044f\u0442\u0438\u043b\u0435\u0442\u0438\u044f \u043d\u0430\u0437\u0430\u0434, \u0430 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0447\u0430\u0441\u0442\u044b\u0445 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0443 \u0442\u0435\u0445, \u043a\u0442\u043e \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0441\u044f \u0441\u043e Spring Batch, \u0437\u0432\u0443\u0447\u0430\u043b \u0442\u0430\u043a: \u00ab\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e\u0439 \u0448\u0442\u0443\u043a\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a SQL-\u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445?\u00bb \u041e\u0442\u0432\u0435\u0442, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e Spring Batch \u0432\u0435\u0434\u0435\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0439\u0448\u0438\u0439 \u0443\u0447\u0435\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u0448\u0430\u0433\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432 <code>JobRepository<\/code>, \u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u0433\u043e\u0434\u044b \u044d\u0442\u043e\u0442 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0435 \u2014 SQL. \u0415\u0441\u043b\u0438 \u0432\u044b \u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432\u043e \u0436\u0438\u043b\u0438 \u0432 \u043c\u0438\u0440\u0435 MongoDB, \u0432\u0430\u043c \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u0430\u0449\u0438\u0442\u044c \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 Postgres \u0438\u043b\u0438 MySQL \u043b\u0438\u0448\u044c \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b Batch \u043c\u043e\u0433 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c, \u0447\u0442\u043e \u043e\u043d \u0441\u0434\u0435\u043b\u0430\u043b \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0432\u0442\u043e\u0440\u043d\u0438\u043a.<\/p>\n<p>\u0412 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 Spring Batch <code>JobRepository<\/code> \u0431\u044b\u043b \u043e\u0442\u0432\u044f\u0437\u0430\u043d \u043e\u0442 JDBC, \u0430 Spring Boot 4.1 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0434\u043e\u0432\u043e\u0434\u0438\u0442 \u044d\u0442\u043e\u0442 \u043e\u043f\u044b\u0442 \u0434\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>spring-boot-starter-batch-data-mongodb<\/code>. \u0412\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0435 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 zero-config-\u043e\u043f\u044b\u0442 Boot \u0434\u043b\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 batch-\u0437\u0430\u0434\u0430\u0447, \u043a\u0430\u043a\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 JDBC \u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430\u043b\u0438\u0441\u044c \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430.<\/p>\n<p>\u0417\u0430\u043d\u044f\u0442\u043d\u044b\u0439 \u0444\u0430\u043a\u0442: \u0434\u043e\u043a\u0442\u043e\u0440 \u0414\u044d\u0439\u0432 \u0421\u0430\u0439\u0435\u0440, \u0441\u043e\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c Spring Boot, \u0431\u044b\u043b \u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0438 \u043c\u043d\u043e\u0433\u043e\u043b\u0435\u0442\u043d\u0438\u043c \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c Spring Batch. \u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u0435\u0440\u0432\u043e\u0439 \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043b\u044f Spring Boot, \u0431\u044b\u043b\u0430 \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f Spring Batch! \u0422\u0430\u043a \u0447\u0442\u043e, \u043a\u043e\u0433\u0434\u0430 \u044f \u0433\u043e\u0432\u043e\u0440\u044e, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 Spring Boot \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043d\u0430 \u0431\u0430\u0437\u0435 JDBC \u0432 Spring Boot \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u044f <em>\u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0438\u043c\u0435\u044e \u0432 \u0432\u0438\u0434\u0443 \ud83d\ude42<\/em><\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440. \u041e\u043d:<\/p>\n<ul>\n<li>\n<p>\u0425\u0440\u0430\u043d\u0438\u0442 Spring Batch <code>JobRepository<\/code> \u0432 MongoDB \u0447\u0435\u0440\u0435\u0437 \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u0435\u0440 4.1.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0438\u0442\u0430\u0435\u0442 <em>customers.csv<\/em> \u0438\u0437 classpath.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 PostgreSQL customers.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u0441\u0435 \u044d\u0442\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445, \u043f\u043e\u0434\u043d\u044f\u0442\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 compose.yaml \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0432 Java, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0434\u0432\u0430 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code class=\"bash\">docker compose up<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><em>compose.yaml<\/em> \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 MongoDB, \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043a\u0430\u043a \u043e\u0434\u043d\u043e\u0443\u0437\u043b\u043e\u0432\u043e\u0439 replica set \u2014 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 MongoDB \u0432 Batch \u043d\u0443\u0436\u043d\u044b \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0430 \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u043d\u0443\u0436\u0435\u043d replica set, \u2014 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 PostgreSQL \u0434\u043b\u044f \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Grafana LGTM \u0434\u043b\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0441\u0442\u0438, \u0435\u0441\u043b\u0438 \u043e\u043d \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>\u0417\u0430\u0434\u0430\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c, \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441: extraction, transformation, load, \u0442\u043e \u0435\u0441\u0442\u044c \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430. \u041e\u043d \u0447\u0438\u0442\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <em>customers.csv<\/em> \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 customers \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 PostgreSQL.<\/p>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 Postgres customers; \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 <em>src\/main\/resources\/schema.sql<\/em>:<\/p>\n<pre><code class=\"sql\">create table if not exists customers (    id    serial primary key,    name  varchar(255),    email varchar(255));<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>SQL-\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Spring Boot (<code>spring.sql.init.mode=always<\/code>) \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u0421\u0442\u043e\u0440\u043e\u043d\u0430 MongoDB \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0430\u043a \u0436\u0435 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e \u2014 <code>spring.batch.data.mongodb.schema.initialize=true<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043d\u043e\u0432\u043e\u043c\u0443 \u0441\u0442\u0430\u0440\u0442\u0435\u0440\u0443 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 <code>JobRepository<\/code>.<\/p>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b <em>application.properties<\/em>:<\/p>\n<pre><code class=\"json\">spring.mongodb.host=localhostspring.mongodb.port=27017spring.mongodb.database=mydatabasespring.batch.data.mongodb.schema.initialize=truespring.datasource.url=jdbc:postgresql:\/\/localhost\/mydatabasespring.datasource.username=myuserspring.datasource.password=secret<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u043e\u0442 \u041c\u0438\u0445\u0430\u0438\u043b\u0430 \u041f\u043e\u043b\u0438\u0432\u0430\u0445\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0422\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Spring Boot Docker Compose starter, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0437\u0431\u0430\u0432\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043e\u0442 \u0432\u0441\u0435\u0439 \u0440\u0443\u0447\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (\u043e\u043f\u044f\u0442\u044c \u0436\u0435, \u0435\u0441\u043b\u0438 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u0440\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 &#171;demo&#187; \u043a\u0435\u0439\u0441).<\/p>\n<p>\u041c\u044b \u0442\u0430\u043a\u0436\u0435 \u043e \u043d\u0435\u043c \u043f\u0438\u0441\u0430\u043b\u0438:<\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/spring_aio\/articles\/1031216\/\">https:\/\/habr.com\/ru\/companies\/spring_aio\/articles\/1031216\/<\/a><\/p>\n<\/div>\n<\/details>\n<h3>\u0417\u0430\u0434\u0430\u043d\u0438\u0435<\/h3>\n<p>\u041d\u0430\u0448 batch job \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f etl \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0434\u0432\u0430 \u0448\u0430\u0433\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"java\">@BeanJob job(@Qualifier(STEP_RESET) Step stepReset,        @Qualifier(STEP_FILES_TO_DB) Step stepFilesToDb) {    return new JobBuilder(\"etl\", this.repository)            .start(stepReset)            .next(stepFilesToDb)            .incrementer(new RunIdIncrementer())            .build();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 reset \u2014 tasklet, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0446\u0435\u043b\u0435\u0432\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0437\u0430\u0442\u0435\u043c files-to-db \u2014 reader \u2192 processor \u2192 writer, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435. <code>RunIdIncrementer<\/code> \u2014 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u043d\u043e \u0432\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c: \u043e\u043d \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>run.id<\/code> \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435, \u0447\u0442\u043e\u0431\u044b Spring Batch \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u043a\u0430\u043a \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u0430 \u043d\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0443\u0436\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435.<\/p>\n<h3>\u0428\u0430\u0433 \u043f\u0435\u0440\u0432\u044b\u0439: Reset<\/h3>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0438\u043f \u0448\u0430\u0433\u0430 \u0432 Spring Batch \u2014 \u044d\u0442\u043e <code>Tasklet<\/code>: \u0435\u0434\u0438\u043d\u044b\u0439 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u0435\u0437 \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u042d\u0442\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0442\u043e-\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c. \u0417\u0434\u0435\u0441\u044c \u2014 \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u0447\u0438\u0441\u0442\u043e\u0433\u043e \u043b\u0438\u0441\u0442\u0430:<\/p>\n<pre><code class=\"java\">@Bean(STEP_RESET)Step cleanTableStep(JdbcClient db, JobRepository repository) {    return new StepBuilder(\"reset\", repository)            .tasklet((contribution, chunkContext) -&gt; {                db.sql(\"delete from customers\").update();                return RepeatStatus.FINISHED;            })            .build();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>Tasklet<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>RepeatStatus.FINISHED<\/code>, \u0438 \u043c\u044b \u0434\u0432\u0438\u0436\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<h3>\u0428\u0430\u0433 \u0432\u0442\u043e\u0440\u043e\u0439: reader, processor, writer<\/h3>\n<p>\u0421\u0430\u043c\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0448\u0430\u0433 \u2014 chunked-\u0448\u0430\u0433. \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d Spring Batch \u2014 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0435\u0433\u043e, \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u044c chunk, \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c chunk. Reader \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 <em>customers.csv<\/em>:<\/p>\n<pre><code class=\"java\">@BeanFlatFileItemReader&lt;Customer&gt; customerFlatFileItemReader(        @Value(\"classpath:\/customers.csv\") Resource csv) {    return new FlatFileItemReaderBuilder&lt;Customer&gt;()            .name(\"customer-reader\")            .resource(csv)            .delimited(c -&gt; c.delimiter(\",\").names(\"id\", \"name\", \"email\"))            .fieldSetMapper(fs -&gt; new Customer(                    fs.readInt(\"id\"),                    fs.readString(\"name\"),                    fs.readString(\"email\")))            .build();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u0430\u043c CSV:<\/p>\n<pre><code class=\"json\">id,name,email1,josh,josh@joshlong.com2,dashaun,dashaun@dashaun.com3,james,james@jamesward.dev<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u0434\u0435\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u0430.<\/p>\n<p><code>Writer<\/code> \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 chunk \u0432 Postgres, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <code>ON CONFLICT DO NOTHING<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0438 \u043d\u0435 \u043f\u0430\u0434\u0430\u043b\u0438 \u0438\u0437-\u0437\u0430 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043f\u043e \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443:<\/p>\n<pre><code class=\"java\">    @Bean    FlatFileItemReader&lt;Customer&gt; customerFlatFileItemReader(@Value(\"classpath:\/customers.csv\") Resource csv) {        return new FlatFileItemReaderBuilder&lt;Customer&gt;() \/\/                .name(\"customer-reader\")                .resource(csv)                .delimited(c -&gt; c.delimiter(\",\").names(\"id\", \"name\", \"email\"))                .targetType(Customer.class)                .build();    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410 \u0441\u0430\u043c \u0448\u0430\u0433 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0441\u043a\u0432\u043e\u0437\u043d\u044b\u043c processor \u2014 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u043c\u0435\u0441\u0442\u043e\u043c, \u043a\u0443\u0434\u0430 \u043f\u043e\u0437\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043e\u0431\u043e\u0433\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e, \u2014 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c chunk, \u0440\u0430\u0432\u043d\u044b\u043c 10:<\/p>\n<pre><code class=\"java\">    @Bean    JdbcBatchItemWriter&lt;Customer&gt; customerJdbcBatchItemWriter(DataSource dataSource) {        return new JdbcBatchItemWriterBuilder&lt;Customer&gt;()\/\/                .assertUpdates(true)\/\/                .dataSource(dataSource)\/\/                .sql(\"INSERT INTO customers(id, name, email) VALUES (:id, :name, :email) on conflict do nothing\")\/\/                .beanMapped()\/\/                .itemPreparedStatementSetter((item, ps) -&gt; {                    ps.setInt(1, item.id());                    ps.setString(2, item.name());                    ps.setString(3, item.email());                })\/\/                .build();    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c <code>faultTolerant()<\/code> \u0438 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 retry \u2014 Spring Batch \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0445 <code>IllegalArgumentException<\/code>, \u0434\u043e \u0434\u0435\u0441\u044f\u0442\u0438 \u0440\u0430\u0437, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u043c\u0435\u0442\u0438\u0442 chunk \u043a\u0430\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439. \u042d\u0442\u043e \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u0441\u044e \u201c\u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044e\u201d \u0437\u0430 \u0432\u0430\u0441 \u0432\u0435\u0434\u0435\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u0436\u0438\u0432\u0435\u0442 \u0432 MongoDB.<\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a<\/h3>\n<p>\u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c Docker Compose:<\/p>\n<pre><code class=\"bash\">.\/mvnw spring-boot:run<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, reset \u043e\u0447\u0438\u0449\u0430\u0435\u0442 Postgres, files-to-db \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442 CSV \u0447\u0435\u0440\u0435\u0437 chunk-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0432 Postgres, \u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438, \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0441\u0442\u0430\u0442\u0443\u0441 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043c\u0435\u0442\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 MongoDB. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 mongosh \u2014 \u0438 \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0435 Batch-\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438: <code>BATCH_JOB_INSTANCE<\/code>, <code>BATCH_JOB_EXECUTION<\/code>, <code>BATCH_STEP_EXECUTION<\/code>. \u0422\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b, \u0430 \u043d\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.<\/p>\n<h3>\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0441\u0442\u044c<\/h3>\n<p>Spring Batch-\u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0442 \u043c\u0430\u0441\u0441\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 Spring <code>ApplicationEvents<\/code>! \u042f \u0441\u043b\u0443\u0448\u0430\u044e \u043e\u0434\u043d\u043e \u0438\u0437 \u043d\u0438\u0445 \u2014 <code>JobExecutionEvent<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u043e\u0441\u044c, \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u043b\u0438 \u043d\u0435\u0442.<\/p>\n<pre><code class=\"java\">    @EventListener    void after(JobExecutionEvent event) {        IO.println(\"Job execution #\" + event.getJobExecution() + \" finished\");    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 Spring Initializr, \u044f \u043d\u0435 \u0437\u0430\u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438 OpenTelemetry Spring Boot starter. Spring Boot \u0438 Micrometer \u0434\u0430\u0432\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 OpenTelemetry, \u043d\u043e \u0440\u0430\u043d\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u043d\u044f. \u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u0432 classpath \u0435\u0441\u0442\u044c OpenTelemetry starter, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u0432 \u043b\u044e\u0431\u043e\u0439 OpenTelemetry endpoint \u2014 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0440\u0442 3000. \u0415\u0441\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 Docker Compose \u0432 Spring Initializr, \u043e\u043d \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0434\u0430\u0441\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e Grafana, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u044c OpenTelemetry-\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 3000.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 <em>localhost:3000<\/em>, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 Drilldown, \u0437\u0430\u0442\u0435\u043c Metrics \u0438 \u043d\u0430\u0439\u0434\u0438\u0442\u0435 <code>spring_batch<\/code> \u0432 \u043f\u043e\u043b\u0435 \u043f\u043e\u0438\u0441\u043a\u0430.<\/p>\n<p>\u041b\u0438\u0431\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c<a href=\"http:\/\/localhost:8080\/actuator\/metrics\"> http:\/\/localhost:8080\/actuator\/metrics<\/a> \u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435 \u0436\u0435 \u043c\u0435\u0442\u0440\u0438\u043a\u0438. \u041d\u043e \u043c\u043d\u0435 \u043d\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u044f\u0440\u043a\u0438\u0435 \u0438 \u043a\u0440\u0430\u0441\u043e\u0447\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 Grafana \u043c\u0435\u043d\u044f \u0432\u0435\u0441\u044c\u043c\u0430 \u0440\u0430\u0434\u0443\u0435\u0442.<\/p>\n<h3>\u0411\u043e\u043d\u0443\u0441: Native Images \u0441 GraalVM<\/h3>\n<p>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f native image \u0432 GraalVM \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043d\u0438\u0437\u0438\u0442\u044c \u043e\u0431\u0449\u0435\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438. Spring Batch \u0443\u0436\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 GraalVM native images, \u043d\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u043e\u0432\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u0447\u0435\u0441\u0442\u044c. \u0418 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u044b\u0445 schema-\u0444\u0430\u0439\u043b\u043e\u0432.<\/p>\n<pre><code class=\"java\">    static class Hints implements RuntimeHintsRegistrar {        @Override        public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) {            for (var c : new Class[]{                    org.springframework.batch.core.repository.persistence.JobInstance.class,                    org.springframework.batch.core.repository.persistence.ExecutionContext.class,                    org.springframework.batch.core.repository.persistence.ExitStatus.class,                    org.springframework.batch.core.repository.persistence.StepExecution.class,                    org.springframework.batch.core.repository.persistence.JobExecution.class,                    org.springframework.batch.core.repository.persistence.JobParameter.class,            }) {                hints.reflection().registerType(c, MemberCategory.values());            }            var prefix = \"org\/springframework\/batch\/core\/\";            for (var r : new String[]{                    \"schema-mongodb\", \/\/                    \"schema-drop-mongodb\"}) {                for (var suffix : \"jsonl,js\".split(\",\")) {                    var path = prefix + r + \".\" + suffix;                    var resource = new ClassPathResource(path);                    if (resource.exists()) {                        hints.resources().registerResource(resource);                    }                }            }        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418 \u043d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0438\u0442\u044c GraalVM \u043e <em>customers.csv<\/em>.<\/p>\n<pre><code class=\"java\">    static class ResourceHints implements RuntimeHintsRegistrar {        @Override        public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {            hints.reflection().registerType(Customer.class, MemberCategory.values());            hints.resources().registerResource(new ClassPathResource(\"\/customers.csv\"));        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u043e\u0431\u0430 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u044d\u0442\u043e \u0432 \u043a\u043b\u0430\u0441\u0441 <code>BatchConfiguration<\/code> \u0438\u043b\u0438 \u0432 \u043b\u044e\u0431\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u0441 <code>@Configuration<\/code>:<\/p>\n<pre><code class=\"java\">@ImportRuntimeHints({BatchConfiguration.ResourceHints.class, BatchConfiguration.Hints.class})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c GraalVM native image \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u042f \u0437\u0430\u043f\u0438\u0441\u0430\u043b \u0448\u0430\u0433\u0438 \u0432 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 <em>native.sh<\/em> \u0432 \u043a\u043e\u0440\u043d\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f:<\/p>\n<pre><code class=\"bash\">#!\/usr\/bin\/env bashls -la target &amp;&amp; rm -rf target.\/mvnw -DskipTests -Pnative native:compile.\/target\/batch<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435: <em>.\/target\/batch<\/em> \u2014 \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u043e\u043d\u043e \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435 RAM, \u0447\u0435\u043c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043d\u0430 JVM. \u041d\u0430 \u043c\u043e\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u2014 Apple M5 \u0441 macOS \u2014 \u043e\u043d\u043e \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0437\u0430 \u043e\u0434\u043d\u0443 \u0434\u0435\u0441\u044f\u0442\u0443\u044e \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043e\u043a\u043e\u043b\u043e 150 \u041c\u0411 RAM. \u0414\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0435 batch-\u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u0442\u0435\u043c \u0432\u0435\u0449\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0430\u0436\u0435\u043d \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442, \u043d\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u044f RAM \u043f\u0440\u0438\u044f\u0442\u043d\u0430, \u0430 \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u043c\u0435\u0448\u0430\u0435\u0442.<\/p>\n<h3>\u041b\u0435\u043d\u0438\u0432\u044b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f DataSource<\/h3>\n<p>\u0415\u0449\u0435 \u043e\u0434\u043d\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u043e\u0431\u0449\u0435\u043c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0435 \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0435\u043d\u044f\u0435\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0443 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443, \u043d\u043e \u0441\u0430\u043c\u0430 \u043f\u043e \u0441\u0435\u0431\u0435 \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u0440\u0438\u044f\u0442\u043d\u0430: \u0432 Spring Boot 4.1 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043b\u0435\u043d\u0438\u0432\u043e\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u041f\u043e\u043c\u043d\u0438\u0442\u0435: \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e Spring Boot \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 DataSource \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0438, \u0447\u0442\u043e \u0432\u044b \u044d\u0442\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435. \u042d\u0442\u043e\u0439 \u043f\u043b\u0430\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 Spring Boot <code>spring.datasource.connection-fetch=lazy<\/code>.<\/p>\n<h3>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438<\/h3>\n<p>\u041a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a href=\"https:\/\/github.com\/coffee-software-show\/2026-06-21-boot-41-batch-and-mongodb\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h3>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e<\/h3>\n<p>\u0418\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0432\u044f\u0437\u043a\u0430 Spring Batch \u0441 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043f\u0440\u0430\u0433\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u043c \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441\u043e\u043c, \u0430 \u043d\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u043c \u0438\u0434\u0435\u0430\u043b\u043e\u043c. \u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u043d \u0441\u0434\u0435\u043b\u0430\u043b, \u0438 SQL \u0431\u044b\u043b \u043f\u0443\u0442\u0435\u043c \u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448\u0435\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f. \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f <code>JobRepository<\/code> \u043f\u043e-\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443 \u043e\u0442\u0432\u044f\u0437\u0430\u043d\u0430, \u0430 Spring Boot 4.1 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u043f\u0435\u0440\u0432\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0443\u044e \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f MongoDB, \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u043c \u043d\u0430 document stores, \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u0435\u0440\u0436\u0430\u0442\u044c JDBC-\u0431\u0430\u0437\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0434\u0438 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0433\u043e\u0434\u0438\u0442\u044c batch-\u0441\u043b\u043e\u044e.<\/p>\n<p>\u0412\u044b\u0431\u0438\u0440\u0430\u0439\u0442\u0435 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0432\u0430\u0448\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u043c. Spring Batch \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u0432\u0430\u0448 \u0432\u044b\u0431\u043e\u0440.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/258\/484\/92d\/25848492d4cd2dcd1df595e475569a9a.png\" width=\"1560\" height=\"334\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/258\/484\/92d\/25848492d4cd2dcd1df595e475569a9a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/258\/484\/92d\/25848492d4cd2dcd1df595e475569a9a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><a href=\"https:\/\/t.me\/+acrI2N6q080wZjM6\">\u041f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0439\u0442\u0435\u0441\u044c<\/a>\u00a0\u043a\u00a0\u0440\u0443\u0441\u0441\u043a\u043e\u044f\u0437\u044b\u0447\u043d\u043e\u043c\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043d\u0430\u00a0Spring Boot \u0432\u00a0\u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u00a0\u2014\u00a0<a href=\"https:\/\/t.me\/+acrI2N6q080wZjM6\">Spring \u0410\u0439\u041e<\/a>, \u0447\u0442\u043e\u0431\u044b\u00a0\u0431\u044b\u0442\u044c \u0432\u00a0\u043a\u0443\u0440\u0441\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u0438\u0437\u00a0\u043c\u0438\u0440\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u00a0Spring Boot \u0438 \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e\u00a0\u0441\u00a0\u043d\u0438\u043c \u0441\u0432\u044f\u0437\u0430\u043d\u043e.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1052358\/\">https:\/\/habr.com\/ru\/articles\/1052358\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Spring Batch \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0437\u0430 \u043c\u043d\u043e\u0433\u043e \u043b\u0435\u0442 \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f MongoDB, \u0438 \u0435\u0433\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u043b\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 SQL-\u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u0439 Spring Batch.\u041d\u043e \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0434\u0435\u0441\u044f\u0442\u0438\u043b\u0435\u0442\u0438\u044f \u043d\u0430\u0437\u0430\u0434, \u0430 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0447\u0430\u0441\u0442\u044b\u0445 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0443 \u0442\u0435\u0445, \u043a\u0442\u043e \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0441\u044f \u0441\u043e Spring Batch, \u0437\u0432\u0443\u0447\u0430\u043b \u0442\u0430\u043a: \u00ab\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e\u0439 \u0448\u0442\u0443\u043a\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a SQL-\u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445?\u00bb \u041e\u0442\u0432\u0435\u0442, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e Spring Batch \u0432\u0435\u0434\u0435\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0439\u0448\u0438\u0439 \u0443\u0447\u0435\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u0448\u0430\u0433\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432 JobRepository, \u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u0433\u043e\u0434\u044b \u044d\u0442\u043e\u0442 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u0435 \u2014 SQL. \u0415\u0441\u043b\u0438 \u0432\u044b \u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432\u043e \u0436\u0438\u043b\u0438 \u0432 \u043c\u0438\u0440\u0435 MongoDB, \u0432\u0430\u043c \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u0430\u0449\u0438\u0442\u044c \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 Postgres \u0438\u043b\u0438 MySQL \u043b\u0438\u0448\u044c \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b Batch \u043c\u043e\u0433 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c, \u0447\u0442\u043e \u043e\u043d \u0441\u0434\u0435\u043b\u0430\u043b \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0432\u0442\u043e\u0440\u043d\u0438\u043a.\u0412 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 Spring Batch JobRepository \u0431\u044b\u043b \u043e\u0442\u0432\u044f\u0437\u0430\u043d \u043e\u0442 JDBC, \u0430 Spring Boot 4.1 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0434\u043e\u0432\u043e\u0434\u0438\u0442 \u044d\u0442\u043e\u0442 \u043e\u043f\u044b\u0442 \u0434\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 spring-boot-starter-batch-data-mongodb. \u0412\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0435 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 zero-config-\u043e\u043f\u044b\u0442 Boot \u0434\u043b\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 batch-\u0437\u0430\u0434\u0430\u0447, \u043a\u0430\u043a\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 JDBC \u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430\u043b\u0438\u0441\u044c \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430.\u0417\u0430\u043d\u044f\u0442\u043d\u044b\u0439 \u0444\u0430\u043a\u0442: \u0434\u043e\u043a\u0442\u043e\u0440 \u0414\u044d\u0439\u0432 \u0421\u0430\u0439\u0435\u0440, \u0441\u043e\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c Spring Boot, \u0431\u044b\u043b \u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0438 \u043c\u043d\u043e\u0433\u043e\u043b\u0435\u0442\u043d\u0438\u043c \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c Spring Batch. \u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u0435\u0440\u0432\u043e\u0439 \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043b\u044f Spring Boot, \u0431\u044b\u043b\u0430 \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f Spring Batch! \u0422\u0430\u043a \u0447\u0442\u043e, \u043a\u043e\u0433\u0434\u0430 \u044f \u0433\u043e\u0432\u043e\u0440\u044e, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 Spring Boot \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043d\u0430 \u0431\u0430\u0437\u0435 JDBC \u0432 Spring Boot \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u044f \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0438\u043c\u0435\u044e \u0432 \u0432\u0438\u0434\u0443 :)\u0412 \u044d\u0442\u043e\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440. \u041e\u043d:\u0425\u0440\u0430\u043d\u0438\u0442 Spring Batch JobRepository \u0432 MongoDB \u0447\u0435\u0440\u0435\u0437 \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u0435\u0440 4.1.\u0427\u0438\u0442\u0430\u0435\u0442 customers.csv \u0438\u0437 classpath.\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 PostgreSQL customers.\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u0441\u0435 \u044d\u0442\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445, \u043f\u043e\u0434\u043d\u044f\u0442\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 compose.yaml \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.\u041f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0432 Java, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0434\u0432\u0430 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:docker compose upcompose.yaml \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 MongoDB, \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043a\u0430\u043a \u043e\u0434\u043d\u043e\u0443\u0437\u043b\u043e\u0432\u043e\u0439 replica set \u2014 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 MongoDB \u0432 Batch \u043d\u0443\u0436\u043d\u044b \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0430 \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u043d\u0443\u0436\u0435\u043d replica set, \u2014 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 PostgreSQL \u0434\u043b\u044f \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Grafana LGTM \u0434\u043b\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0441\u0442\u0438, \u0435\u0441\u043b\u0438 \u043e\u043d \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043f\u043e\u0437\u0436\u0435.\u0417\u0430\u0434\u0430\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c, \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441: extraction, transformation, load, \u0442\u043e \u0435\u0441\u0442\u044c \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430. \u041e\u043d \u0447\u0438\u0442\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 customers.csv \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 customers \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 PostgreSQL.\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 Postgres customers; \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 src\/main\/resources\/schema.sql:create table if not exists customers (    id    serial primary key,    name  varchar(255),    email varchar(255));SQL-\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Spring Boot (spring.sql.init.mode=always) \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u0421\u0442\u043e\u0440\u043e\u043d\u0430 MongoDB \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0442\u0430\u043a \u0436\u0435 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e \u2014 spring.batch.data.mongodb.schema.initialize=true \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043d\u043e\u0432\u043e\u043c\u0443 \u0441\u0442\u0430\u0440\u0442\u0435\u0440\u0443 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 JobRepository.\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b application.properties:spring.mongodb.host=localhostspring.mongodb.port=27017spring.mongodb.database=mydatabasespring.batch.data.mongodb.schema.initialize=truespring.datasource.url=jdbc:postgresql:\/\/localhost\/mydatabasespring.datasource.username=myuserspring.datasource.password=secret\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u043e\u0442 \u041c\u0438\u0445\u0430\u0438\u043b\u0430 \u041f\u043e\u043b\u0438\u0432\u0430\u0445\u0430\u0422\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Spring Boot Docker Compose starter, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0437\u0431\u0430\u0432\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043e\u0442 \u0432\u0441\u0435\u0439 \u0440\u0443\u0447\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (\u043e\u043f\u044f\u0442\u044c \u0436\u0435, \u0435\u0441\u043b\u0438 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u0440\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 &#171;demo&#187; \u043a\u0435\u0439\u0441).\u041c\u044b \u0442\u0430\u043a\u0436\u0435 \u043e \u043d\u0435\u043c \u043f\u0438\u0441\u0430\u043b\u0438:https:\/\/habr.com\/ru\/companies\/spring_aio\/articles\/1031216\/\u0417\u0430\u0434\u0430\u043d\u0438\u0435\u041d\u0430\u0448 batch job \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f etl \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0434\u0432\u0430 \u0448\u0430\u0433\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e:@BeanJob job(@Qualifier(STEP_RESET) Step stepReset,        @Qualifier(STEP_FILES_TO_DB) Step stepFilesToDb) {    return new JobBuilder(&#171;etl&#187;, this.repository)            .start(stepReset)            .next(stepFilesToDb)            .incrementer(new RunIdIncrementer())            .build();}\u0421\u043d\u0430\u0447\u0430\u043b\u0430 reset \u2014 tasklet, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0446\u0435\u043b\u0435\u0432\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0437\u0430\u0442\u0435\u043c files-to-db \u2014 reader \u2192 processor \u2192 writer, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435. RunIdIncrementer \u2014 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u043d\u043e \u0432\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c: \u043e\u043d \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 run.id \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435, \u0447\u0442\u043e\u0431\u044b Spring Batch \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u043a\u0430\u043a \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u0430 \u043d\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0443\u0436\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435.\u0428\u0430\u0433 \u043f\u0435\u0440\u0432\u044b\u0439: Reset\u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0438\u043f \u0448\u0430\u0433\u0430 \u0432 Spring Batch \u2014 \u044d\u0442\u043e Tasklet: \u0435\u0434\u0438\u043d\u044b\u0439 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u0435\u0437 \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u042d\u0442\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0442\u043e-\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c. \u0417\u0434\u0435\u0441\u044c \u2014 \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u0447\u0438\u0441\u0442\u043e\u0433\u043e \u043b\u0438\u0441\u0442\u0430:@Bean(STEP_RESET)Step cleanTableStep(JdbcClient db, JobRepository repository) {    return new StepBuilder(&#171;reset&#187;, repository)            .tasklet((contribution, chunkContext) -&gt; {                db.sql(&#171;delete from customers&#187;).update();                return RepeatStatus.FINISHED;            })            .build();}Tasklet \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 RepeatStatus.FINISHED, \u0438 \u043c\u044b \u0434\u0432\u0438\u0436\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435.\u0428\u0430\u0433 \u0432\u0442\u043e\u0440\u043e\u0439: reader, processor, writer\u0421\u0430\u043c\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0448\u0430\u0433 \u2014 chunked-\u0448\u0430\u0433. \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d Spring Batch \u2014 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0435\u0433\u043e, \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u044c chunk, \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c chunk. Reader \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 customers.csv:@BeanFlatFileItemReader&lt;Customer&gt; customerFlatFileItemReader(        @Value(&#171;classpath:\/customers.csv&#187;) Resource csv) {    return new FlatFileItemReaderBuilder&lt;Customer&gt;()            .name(&#171;customer-reader&#187;)            .resource(csv)            .delimited(c -&gt; c.delimiter(&#171;,&#187;).names(&#171;id&#187;, &#171;name&#187;, &#171;email&#187;))            .fieldSetMapper(fs -&gt; new Customer(                    fs.readInt(&#171;id&#187;),                    fs.readString(&#171;name&#187;),                    fs.readString(&#171;email&#187;)))            .build();}\u0421\u0430\u043c CSV:id,name,email1,josh,josh@joshlong.com2,dashaun,dashaun@dashaun.com3,james,james@jamesward.dev\u0418\u0434\u0435\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u0430.Writer \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 chunk \u0432 Postgres, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f ON CONFLICT DO NOTHING, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0438 \u043d\u0435 \u043f\u0430\u0434\u0430\u043b\u0438 \u0438\u0437-\u0437\u0430 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043f\u043e \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443:    @Bean    FlatFileItemReader&lt;Customer&gt; customerFlatFileItemReader(@Value(&#171;classpath:\/customers.csv&#187;) Resource csv) {        return new FlatFileItemReaderBuilder&lt;Customer&gt;() \/\/                .name(&#171;customer-reader&#187;)                .resource(csv)                .delimited(c -&gt; c.delimiter(&#171;,&#187;).names(&#171;id&#187;, &#171;name&#187;, &#171;email&#187;))                .targetType(Customer.class)                .build();    }\u0410 \u0441\u0430\u043c \u0448\u0430\u0433 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0441\u043a\u0432\u043e\u0437\u043d\u044b\u043c processor \u2014 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u043c\u0435\u0441\u0442\u043e\u043c, \u043a\u0443\u0434\u0430 \u043f\u043e\u0437\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043e\u0431\u043e\u0433\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e, \u2014 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c chunk, \u0440\u0430\u0432\u043d\u044b\u043c 10:    @Bean    JdbcBatchItemWriter&lt;Customer&gt; customerJdbcBatchItemWriter(DataSource dataSource) {        return new JdbcBatchItemWriterBuilder&lt;Customer&gt;()\/\/                .assertUpdates(true)\/\/                .dataSource(dataSource)\/\/                .sql(&#171;INSERT INTO customers(id, name, email) VALUES (:id, :name, :email) on conflict do nothing&#187;)\/\/                .beanMapped()\/\/                .itemPreparedStatementSetter((item, ps) -&gt; {                    ps.setInt(1, item.id());                    ps.setString(2, item.name());                    ps.setString(3, item.email());                })\/\/                .build();    }\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c faultTolerant() \u0438 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 retry \u2014 Spring Batch \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0445 IllegalArgumentException, \u0434\u043e \u0434\u0435\u0441\u044f\u0442\u0438 \u0440\u0430\u0437, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u043c\u0435\u0442\u0438\u0442 chunk \u043a\u0430\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439. \u042d\u0442\u043e \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u0441\u044e \u201c\u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044e\u201d \u0437\u0430 \u0432\u0430\u0441 \u0432\u0435\u0434\u0435\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u0436\u0438\u0432\u0435\u0442 \u0432 MongoDB.\u0417\u0430\u043f\u0443\u0441\u043a\u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c Docker Compose:.\/mvnw spring-boot:run\u0417\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, reset \u043e\u0447\u0438\u0449\u0430\u0435\u0442 Postgres, files-to-db \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442 CSV \u0447\u0435\u0440\u0435\u0437 chunk-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0432 Postgres, \u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438, \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0441\u0442\u0430\u0442\u0443\u0441 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043c\u0435\u0442\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 MongoDB. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 mongosh \u2014 \u0438 \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0435 Batch-\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438: BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_STEP_EXECUTION. \u0422\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b, \u0430 \u043d\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0441\u0442\u044cSpring Batch-\u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0442 \u043c\u0430\u0441\u0441\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 Spring ApplicationEvents! \u042f \u0441\u043b\u0443\u0448\u0430\u044e \u043e\u0434\u043d\u043e \u0438\u0437 \u043d\u0438\u0445 \u2014 JobExecutionEvent, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u043e\u0441\u044c, \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u043b\u0438 \u043d\u0435\u0442.    @EventListener    void after(JobExecutionEvent event) {        IO.println(&#171;Job execution #&#187; + event.getJobExecution() + &#187; finished&#187;);    }\u041a\u043e\u0433\u0434\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 Spring Initializr, \u044f \u043d\u0435 \u0437\u0430\u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438 OpenTelemetry Spring Boot starter. Spring Boot \u0438 Micrometer \u0434\u0430\u0432\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 OpenTelemetry, \u043d\u043e \u0440\u0430\u043d\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u043d\u044f. \u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u0432 classpath \u0435\u0441\u0442\u044c OpenTelemetry starter, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u0432 \u043b\u044e\u0431\u043e\u0439 OpenTelemetry endpoint \u2014 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0440\u0442 3000. \u0415\u0441\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 Docker Compose \u0432 Spring Initializr, \u043e\u043d \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0434\u0430\u0441\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e Grafana, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u044c OpenTelemetry-\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 3000.\u0418\u0442\u0430\u043a, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 localhost:3000, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 Drilldown, \u0437\u0430\u0442\u0435\u043c Metrics \u0438 \u043d\u0430\u0439\u0434\u0438\u0442\u0435 spring_batch \u0432 \u043f\u043e\u043b\u0435 \u043f\u043e\u0438\u0441\u043a\u0430.\u041b\u0438\u0431\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c http:\/\/localhost:8080\/actuator\/metrics \u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435 \u0436\u0435 \u043c\u0435\u0442\u0440\u0438\u043a\u0438. \u041d\u043e \u043c\u043d\u0435 \u043d\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u044f\u0440\u043a\u0438\u0435 \u0438 \u043a\u0440\u0430\u0441\u043e\u0447\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 Grafana \u043c\u0435\u043d\u044f \u0432\u0435\u0441\u044c\u043c\u0430 \u0440\u0430\u0434\u0443\u0435\u0442.\u0411\u043e\u043d\u0443\u0441: Native Images \u0441 GraalVM\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f native image \u0432 GraalVM \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043d\u0438\u0437\u0438\u0442\u044c \u043e\u0431\u0449\u0435\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438. Spring Batch \u0443\u0436\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 GraalVM native images, \u043d\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u043e\u0432\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u0447\u0435\u0441\u0442\u044c. \u0418 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u044b\u0445 schema-\u0444\u0430\u0439\u043b\u043e\u0432.    static class Hints implements RuntimeHintsRegistrar {        @Override        public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) {            for (var c : new Class[]{                    org.springframework.batch.core.repository.persistence.JobInstance.class,                    org.springframework.batch.core.repository.persistence.ExecutionContext.class,                    org.springframework.batch.core.repository.persistence.ExitStatus.class,                    org.springframework.batch.core.repository.persistence.StepExecution.class,                    org.springframework.batch.core.repository.persistence.JobExecution.class,                 &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-485192","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/485192","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=485192"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/485192\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=485192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=485192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=485192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}