JDBC Batch Processing
Executing multiple SQL statements efficiently in batches
📦 Batch Processing
Batch processing allows you to execute multiple SQL statements together as a group, improving performance by reducing network round trips and database overhead when processing large amounts of data.
// Basic batch processing
stmt.addBatch("INSERT INTO users VALUES (1, 'John')");
stmt.addBatch("INSERT INTO users VALUES (2, 'Jane')");
int[] results = stmt.executeBatch();
Batch Processing Benefits
Performance
Faster execution of multiple statements
// Execute 1000 inserts in one batch
Network Efficiency
Reduces network round trips
// One network call instead of many
Resource Optimization
Better database resource utilization
stmt.executeBatch(); // Optimized execution
Transaction Control
All operations in single transaction
// Atomic batch execution
🔹 Statement Batch Processing
Using Statement for batch processing multiple SQL commands:
import java.sql.*;
public class StatementBatch {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String username = "root";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, username, password)) {
// Disable auto-commit for better performance
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
// Create table
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS employees (" +
"id INT PRIMARY KEY, " +
"name VARCHAR(50), " +
"department VARCHAR(30), " +
"salary DECIMAL(10,2))");
System.out.println("Adding statements to batch...");
// Add multiple INSERT statements to batch
stmt.addBatch("INSERT INTO employees VALUES (1, 'John Smith', 'IT', 75000.00)");
stmt.addBatch("INSERT INTO employees VALUES (2, 'Jane Doe', 'HR', 65000.00)");
stmt.addBatch("INSERT INTO employees VALUES (3, 'Mike Johnson', 'Finance', 70000.00)");
stmt.addBatch("INSERT INTO employees VALUES (4, 'Sarah Wilson', 'IT', 80000.00)");
stmt.addBatch("INSERT INTO employees VALUES (5, 'Tom Brown', 'Marketing', 60000.00)");
// Add UPDATE statements to batch
stmt.addBatch("UPDATE employees SET salary = salary * 1.1 WHERE department = 'IT'");
stmt.addBatch("UPDATE employees SET department = 'Human Resources' WHERE department = 'HR'");
System.out.println("Executing batch...");
// Execute all statements in batch
int[] results = stmt.executeBatch();
// Commit the transaction
conn.commit();
System.out.println("Batch executed successfully!");
System.out.println("Results:");
for (int i = 0; i < results.length; i++) {
System.out.println("Statement " + (i + 1) + ": " + results[i] + " rows affected");
}
// Verify the results
ResultSet rs = stmt.executeQuery("SELECT * FROM employees ORDER BY id");
System.out.println("\nEmployees in database:");
System.out.println("ID\tName\t\tDepartment\t\tSalary");
System.out.println("--------------------------------------------------------");
while (rs.next()) {
System.out.printf("%d\t%-15s\t%-15s\t$%.2f%n",
rs.getInt("id"),
rs.getString("name"),
rs.getString("department"),
rs.getDouble("salary"));
}
} catch (SQLException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output:
Adding statements to batch...
Executing batch...
Batch executed successfully!
Results:
Statement 1: 1 rows affected
Statement 2: 1 rows affected
Statement 3: 1 rows affected
Statement 4: 1 rows affected
Statement 5: 1 rows affected
Statement 6: 2 rows affected
Statement 7: 1 rows affected
Employees in database:
ID Name Department Salary
--------------------------------------------------------
1 John Smith IT $82500.00
2 Jane Doe Human Resources $65000.00
3 Mike Johnson Finance $70000.00
4 Sarah Wilson IT $88000.00
5 Tom Brown Marketing $60000.00
🔹 PreparedStatement Batch Processing
Using PreparedStatement for efficient batch processing with parameters:
import java.sql.*;
public class PreparedStatementBatch {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String username = "root";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, username, password)) {
conn.setAutoCommit(false);
// Prepare the INSERT statement
String insertSQL = "INSERT INTO employees (id, name, department, salary) VALUES (?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
System.out.println("Preparing batch insert...");
// Employee data to insert
Object[][] employees = {
{6, "Alice Cooper", "IT", 85000.00},
{7, "Bob Martin", "Finance", 72000.00},
{8, "Carol White", "Marketing", 68000.00},
{9, "David Lee", "IT", 90000.00},
{10, "Emma Davis", "HR", 63000.00},
{11, "Frank Miller", "Finance", 75000.00},
{12, "Grace Taylor", "Marketing", 66000.00},
{13, "Henry Wilson", "IT", 88000.00},
{14, "Ivy Chen", "HR", 64000.00},
{15, "Jack Robinson", "Finance", 77000.00}
};
// Add each employee to the batch
for (Object[] employee : employees) {
pstmt.setInt(1, (Integer) employee[0]);
pstmt.setString(2, (String) employee[1]);
pstmt.setString(3, (String) employee[2]);
pstmt.setDouble(4, (Double) employee[3]);
pstmt.addBatch(); // Add to batch
}
System.out.println("Executing batch of " + employees.length + " employees...");
// Execute the batch
long startTime = System.currentTimeMillis();
int[] results = pstmt.executeBatch();
long endTime = System.currentTimeMillis();
// Commit the transaction
conn.commit();
System.out.println("Batch execution completed in " + (endTime - startTime) + " ms");
// Count successful inserts
int successCount = 0;
for (int result : results) {
if (result > 0) successCount++;
}
System.out.println("Successfully inserted " + successCount + " employees");
// Verify total count
Statement countStmt = conn.createStatement();
ResultSet rs = countStmt.executeQuery("SELECT COUNT(*) FROM employees");
if (rs.next()) {
System.out.println("Total employees in database: " + rs.getInt(1));
}
}
} catch (SQLException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output:
Preparing batch insert...
Executing batch of 10 employees...
Batch execution completed in 45 ms
Successfully inserted 10 employees
Total employees in database: 15
🔹 Batch Processing with Error Handling
Handling errors and partial failures in batch processing:
import java.sql.*;
public class BatchErrorHandling {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String username = "root";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, username, password)) {
conn.setAutoCommit(false);
String insertSQL = "INSERT INTO employees (id, name, department, salary) VALUES (?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
System.out.println("Testing batch with potential errors...");
// Add valid records
pstmt.setInt(1, 20);
pstmt.setString(2, "Valid User 1");
pstmt.setString(3, "IT");
pstmt.setDouble(4, 75000.00);
pstmt.addBatch();
pstmt.setInt(1, 21);
pstmt.setString(2, "Valid User 2");
pstmt.setString(3, "Finance");
pstmt.setDouble(4, 80000.00);
pstmt.addBatch();
// Add duplicate ID (will cause error)
pstmt.setInt(1, 1); // This ID already exists
pstmt.setString(2, "Duplicate ID User");
pstmt.setString(3, "HR");
pstmt.setDouble(4, 70000.00);
pstmt.addBatch();
// Add another valid record
pstmt.setInt(1, 22);
pstmt.setString(2, "Valid User 3");
pstmt.setString(3, "Marketing");
pstmt.setDouble(4, 65000.00);
pstmt.addBatch();
try {
// Execute batch
int[] results = pstmt.executeBatch();
conn.commit();
System.out.println("Batch executed successfully!");
for (int i = 0; i < results.length; i++) {
System.out.println("Statement " + (i + 1) + ": " + results[i] + " rows affected");
}
} catch (BatchUpdateException e) {
System.out.println("❌ Batch update exception occurred!");
System.out.println("Error message: " + e.getMessage());
// Get partial results
int[] updateCounts = e.getUpdateCounts();
System.out.println("Partial results:");
for (int i = 0; i < updateCounts.length; i++) {
if (updateCounts[i] >= 0) {
System.out.println("Statement " + (i + 1) + ": SUCCESS (" + updateCounts[i] + " rows)");
} else if (updateCounts[i] == Statement.EXECUTE_FAILED) {
System.out.println("Statement " + (i + 1) + ": FAILED");
} else {
System.out.println("Statement " + (i + 1) + ": UNKNOWN (" + updateCounts[i] + ")");
}
}
// Rollback the transaction
conn.rollback();
System.out.println("🔄 Transaction rolled back");
// Try again with only valid records
System.out.println("\nRetrying with valid records only...");
pstmt.clearBatch();
// Add only valid records
pstmt.setInt(1, 20);
pstmt.setString(2, "Valid User 1");
pstmt.setString(3, "IT");
pstmt.setDouble(4, 75000.00);
pstmt.addBatch();
pstmt.setInt(1, 21);
pstmt.setString(2, "Valid User 2");
pstmt.setString(3, "Finance");
pstmt.setDouble(4, 80000.00);
pstmt.addBatch();
pstmt.setInt(1, 22);
pstmt.setString(2, "Valid User 3");
pstmt.setString(3, "Marketing");
pstmt.setDouble(4, 65000.00);
pstmt.addBatch();
int[] retryResults = pstmt.executeBatch();
conn.commit();
System.out.println("✅ Retry successful! Inserted " + retryResults.length + " records");
}
}
} catch (SQLException e) {
System.out.println("Database error: " + e.getMessage());
}
}
}
Output:
Testing batch with potential errors...
❌ Batch update exception occurred!
Error message: Duplicate entry '1' for key 'PRIMARY'
Partial results:
Statement 1: SUCCESS (1 rows)
Statement 2: SUCCESS (1 rows)
Statement 3: FAILED
🔄 Transaction rolled back
Retrying with valid records only...
✅ Retry successful! Inserted 3 records
🔹 Performance Comparison
Comparing batch processing vs individual statements:
import java.sql.*;
public class PerformanceComparison {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String username = "root";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, username, password)) {
// Create test table
Statement setup = conn.createStatement();
setup.executeUpdate("DROP TABLE IF EXISTS performance_test");
setup.executeUpdate("CREATE TABLE performance_test (id INT PRIMARY KEY, data VARCHAR(100))");
int recordCount = 1000;
// Test 1: Individual statements
System.out.println("Testing individual statements...");
long startTime = System.currentTimeMillis();
conn.setAutoCommit(false);
PreparedStatement individualStmt = conn.prepareStatement(
"INSERT INTO performance_test VALUES (?, ?)");
for (int i = 1; i <= recordCount; i++) {
individualStmt.setInt(1, i);
individualStmt.setString(2, "Data for record " + i);
individualStmt.executeUpdate(); // Execute immediately
}
conn.commit();
long individualTime = System.currentTimeMillis() - startTime;
System.out.println("Individual statements: " + individualTime + " ms");
// Clear table for next test
setup.executeUpdate("DELETE FROM performance_test");
// Test 2: Batch processing
System.out.println("\nTesting batch processing...");
startTime = System.currentTimeMillis();
conn.setAutoCommit(false);
PreparedStatement batchStmt = conn.prepareStatement(
"INSERT INTO performance_test VALUES (?, ?)");
for (int i = 1; i <= recordCount; i++) {
batchStmt.setInt(1, i);
batchStmt.setString(2, "Data for record " + i);
batchStmt.addBatch(); // Add to batch
// Execute batch every 100 records for memory efficiency
if (i % 100 == 0) {
batchStmt.executeBatch();
batchStmt.clearBatch();
}
}
// Execute remaining records
batchStmt.executeBatch();
conn.commit();
long batchTime = System.currentTimeMillis() - startTime;
System.out.println("Batch processing: " + batchTime + " ms");
// Calculate improvement
double improvement = ((double)(individualTime - batchTime) / individualTime) * 100;
System.out.println("\nPerformance improvement: " + String.format("%.1f", improvement) + "%");
System.out.println("Batch processing is " + String.format("%.1f", (double)individualTime / batchTime) + "x faster");
// Verify record count
ResultSet rs = setup.executeQuery("SELECT COUNT(*) FROM performance_test");
if (rs.next()) {
System.out.println("Records inserted: " + rs.getInt(1));
}
} catch (SQLException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output:
Testing individual statements...
Individual statements: 2847 ms
Testing batch processing...
Batch processing: 156 ms
Performance improvement: 94.5%
Batch processing is 18.2x faster
Records inserted: 1000
🔹 Best Practices for Batch Processing
Tips for effective batch processing:
✅ Best Practices:
- Batch Size: Use optimal batch sizes (100-1000 records)
- Memory Management: Clear batches periodically to avoid memory issues
- Transaction Control: Disable auto-commit for better performance
- Error Handling: Always handle BatchUpdateException
- Connection Pooling: Use connection pools for better resource management
❌ Avoid:
- Large Batches: Don't add thousands of statements without executing
- Mixed Operations: Don't mix different types of SQL in same batch
- Auto-commit: Don't leave auto-commit enabled during batch operations
- Ignoring Errors: Always check for partial failures