diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml
index ee4807933a..612070ea10 100644
--- a/persistence-modules/pom.xml
+++ b/persistence-modules/pom.xml
@@ -105,6 +105,7 @@
spring-jooq
spring-mybatis
spring-persistence-simple
+ spring-jdbc-batch
diff --git a/persistence-modules/spring-jdbc-batch/pom.xml b/persistence-modules/spring-jdbc-batch/pom.xml
new file mode 100644
index 0000000000..0401044be1
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+
+ 4.0.0
+
+ spring-jdbc-batch
+ 0.0.1-SNAPSHOT
+ spring-jdbc-batch
+ Demo project for Spring Boot Jdbc batch support
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../../parent-boot-2
+
+
+
+
+ 11
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/SpringJdbcBatchPerformanceApplication.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/SpringJdbcBatchPerformanceApplication.java
new file mode 100644
index 0000000000..aef2100de8
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/SpringJdbcBatchPerformanceApplication.java
@@ -0,0 +1,43 @@
+package com.baeldung.spring.jdbc.batch;
+
+import com.baeldung.spring.jdbc.batch.service.ProductService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringJdbcBatchPerformanceApplication implements CommandLineRunner {
+
+ @Autowired
+ @Qualifier("batchProductService")
+ private ProductService batchProductService;
+ @Autowired
+ @Qualifier("simpleProductService")
+ private ProductService simpleProductService;
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringJdbcBatchPerformanceApplication.class, args);
+ }
+
+ @Override
+ public void run(String... args) throws Exception {
+ int[] recordCounts = { 1, 10, 100, 1000, 10_000, 100_000, 1000_000 };
+
+ for (int recordCount : recordCounts) {
+ long regularElapsedTime = simpleProductService.createProducts(recordCount);
+ long batchElapsedTime = batchProductService.createProducts(recordCount);
+
+ System.out.println("-".repeat(50));
+ System.out.format("%-20s%-5s%-10s%-5s%8sms\n", "Regular inserts", "|", recordCount, "|", regularElapsedTime);
+ System.out.format("%-20s%-5s%-10s%-5s%8sms\n", "Batch inserts", "|", recordCount, "|", batchElapsedTime);
+ System.out.printf("Total gain: %d %s\n", calculateGainInPercent(regularElapsedTime, batchElapsedTime), "%");
+ }
+
+ }
+
+ int calculateGainInPercent(long before, long after) {
+ return (int) Math.floor(100D * (before - after) / before);
+ }
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/config/AppConfig.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/config/AppConfig.java
new file mode 100644
index 0000000000..b0fd111ed2
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/config/AppConfig.java
@@ -0,0 +1,24 @@
+package com.baeldung.spring.jdbc.batch.config;
+
+import com.baeldung.spring.jdbc.batch.repo.BatchProductRepository;
+import com.baeldung.spring.jdbc.batch.repo.SimpleProductRepository;
+import com.baeldung.spring.jdbc.batch.service.ProductService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Clock;
+import java.util.Random;
+
+@Configuration
+public class AppConfig {
+
+ @Bean
+ public ProductService simpleProductService(SimpleProductRepository simpleProductRepository) {
+ return new ProductService(simpleProductRepository, new Random(), Clock.systemUTC());
+ }
+
+ @Bean
+ public ProductService batchProductService(BatchProductRepository batchProductRepository) {
+ return new ProductService(batchProductRepository, new Random(), Clock.systemUTC());
+ }
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/model/Product.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/model/Product.java
new file mode 100644
index 0000000000..6454952fdc
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/model/Product.java
@@ -0,0 +1,54 @@
+package com.baeldung.spring.jdbc.batch.model;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+public class Product {
+ private long id;
+ private String title;
+ private LocalDateTime createdTs;
+ private BigDecimal price;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public LocalDateTime getCreatedTs() {
+ return createdTs;
+ }
+
+ public void setCreatedTs(LocalDateTime createdTs) {
+ this.createdTs = createdTs;
+ }
+
+ public BigDecimal getPrice() {
+ return price;
+ }
+
+ public void setPrice(BigDecimal price) {
+ this.price = price;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("Product{");
+ sb.append("id=").append(id);
+ sb.append(", title='").append(title).append('\'');
+ sb.append(", createdTs=").append(createdTs);
+ sb.append(", price=").append(price);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/BatchProductRepository.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/BatchProductRepository.java
new file mode 100644
index 0000000000..d4a4affd0a
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/BatchProductRepository.java
@@ -0,0 +1,33 @@
+package com.baeldung.spring.jdbc.batch.repo;
+
+import com.baeldung.spring.jdbc.batch.model.Product;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.PreparedStatement;
+import java.sql.Timestamp;
+import java.util.List;
+
+@Repository
+public class BatchProductRepository implements ProductRepository {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ public BatchProductRepository(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @Override
+ @Transactional
+ public void saveAll(List products) {
+ jdbcTemplate.batchUpdate("INSERT INTO PRODUCT (TITLE, CREATED_TS, PRICE) VALUES (?, ?, ?)",
+ products,
+ 100,
+ (PreparedStatement ps, Product product) -> {
+ ps.setString(1, product.getTitle());
+ ps.setTimestamp(2, Timestamp.valueOf(product.getCreatedTs()));
+ ps.setBigDecimal(3, product.getPrice());
+ });
+ }
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/ProductRepository.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/ProductRepository.java
new file mode 100644
index 0000000000..ed193f87dd
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/ProductRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.spring.jdbc.batch.repo;
+
+import com.baeldung.spring.jdbc.batch.model.Product;
+
+import java.util.List;
+
+public interface ProductRepository {
+ void saveAll(List products);
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/SimpleProductRepository.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/SimpleProductRepository.java
new file mode 100644
index 0000000000..3dfb998cba
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/repo/SimpleProductRepository.java
@@ -0,0 +1,29 @@
+package com.baeldung.spring.jdbc.batch.repo;
+
+import com.baeldung.spring.jdbc.batch.model.Product;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+@Repository
+public class SimpleProductRepository implements ProductRepository {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ public SimpleProductRepository(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @Override
+ @Transactional
+ public void saveAll(List products) {
+ for (Product product : products) {
+ jdbcTemplate.update("INSERT INTO PRODUCT (TITLE, CREATED_TS, PRICE) VALUES (?, ?, ?)",
+ product.getTitle(), Timestamp.valueOf(product.getCreatedTs()), product.getPrice());
+ }
+ }
+
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/service/ProductService.java b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/service/ProductService.java
new file mode 100644
index 0000000000..6a3758c07a
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/main/java/com/baeldung/spring/jdbc/batch/service/ProductService.java
@@ -0,0 +1,54 @@
+package com.baeldung.spring.jdbc.batch.service;
+
+import com.baeldung.spring.jdbc.batch.model.Product;
+import com.baeldung.spring.jdbc.batch.repo.ProductRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class ProductService {
+
+ private final ProductRepository productRepository;
+ private final Random random;
+ private final Clock clock;
+
+ public ProductService(ProductRepository productRepository, Random random, Clock clock) {
+ this.productRepository = productRepository;
+ this.random = random;
+ this.clock = clock;
+ }
+
+ @Transactional
+ public long createProducts(int count) {
+ List products = generate(count);
+ long startTime = clock.millis();
+ productRepository.saveAll(products);
+ return clock.millis() - startTime;
+ }
+
+ protected List generate(int count) {
+ final String[] titles = { "car", "plane", "house", "yacht" };
+ final BigDecimal[] prices = {
+ new BigDecimal("12483.12"),
+ new BigDecimal("8539.99"),
+ new BigDecimal("88894"),
+ new BigDecimal("458694")
+ };
+
+ final List products = new ArrayList<>(count);
+
+ for (int i = 0; i < count; i++) {
+ Product product = new Product();
+ product.setCreatedTs(LocalDateTime.now());
+ product.setPrice(prices[random.nextInt(4)]);
+ product.setTitle(titles[random.nextInt(4)]);
+ products.add(product);
+ }
+ return products;
+ }
+}
diff --git a/persistence-modules/spring-jdbc-batch/src/test/java/com/baeldung/spring/jdbc/batch/service/ProductServiceUnitTest.java b/persistence-modules/spring-jdbc-batch/src/test/java/com/baeldung/spring/jdbc/batch/service/ProductServiceUnitTest.java
new file mode 100644
index 0000000000..b242eaa335
--- /dev/null
+++ b/persistence-modules/spring-jdbc-batch/src/test/java/com/baeldung/spring/jdbc/batch/service/ProductServiceUnitTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.jdbc.batch.service;
+
+import com.baeldung.spring.jdbc.batch.repo.ProductRepository;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import java.time.Clock;
+import java.util.Random;
+
+class ProductServiceUnitTest {
+
+ @Mock
+ ProductRepository productRepository;
+ @Mock
+ Random random;
+ @Mock
+ Clock clock;
+ @InjectMocks
+ ProductService productService;
+
+ @Test
+ void testWhenThen() {
+
+ }
+}
\ No newline at end of file