Batch Insert In Java – JDBC
- By Viral Patel on March 1, 2012
Let’s see how we can perform batch insert in Java using JDBC APIs. Although you might already knew this, I will try to explain the basic to a bit complex scenarios.
In this note, we will see how we can use JDBC APIs like
Statement
and PreparedStatement
to insert data in any database in batches. Also we will try to explore scenarios where we can run out of memory and how to optimize the batch operation.So first, the basic API to Insert data in database in batches using Java JDBC.
Simple Batch
I am calling this a simple batch. The requirement is simple. Execute a list of inserts in batch. Instead of hitting database once for each insert statement, we will using JDBC batch operation and optimize the performance.Consider the following code:
Bad Code
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | String [] queries = { "insert into employee (name, city, phone) values ('A', 'X', '123')" , "insert into employee (name, city, phone) values ('B', 'Y', '234')" , "insert into employee (name, city, phone) values ('C', 'Z', '345')" , }; Connection connection = new getConnection(); Statement statemenet = connection.createStatement(); for (String query : queries) { statemenet.execute(query); } statemenet.close(); connection.close(); |
We’ll below is the basic code to perform batch insert. Check it out:
Good Code
1 2 3 4 5 6 7 8 9 | Connection connection = new getConnection(); Statement statemenet = connection.createStatement(); for (String query : queries) { statemenet.addBatch(query); } statemenet.executeBatch(); statemenet.close(); connection.close(); |
addBatch()
method of Statement, instead of directly executing the query. And after adding all the queries we executed them in one go using statement.executeBatch()
method. Nothing fancy, just a simple batch insert.Note that we have taken the queries from a String array. Instead you may want to make it dynamically. For example:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | import java.sql.Connection; import java.sql.Statement; //... Connection connection = new getConnection(); Statement statemenet = connection.createStatement(); for (Employee employee: employees) { String query = "insert into employee (name, city) values('" + employee.getName() + "','" + employee.getCity + "')" ; statemenet.addBatch(query); } statemenet.executeBatch(); statemenet.close(); connection.close(); |
wait.. You must be thinking what about SQL Injection? Creating queries like this dynamically is very prone to SQL injection. And also the insert query has to be compiled each time.
Why not to use
PreparedStatement
instead of simple Statement
. Yes, that can be the solution. Check out the below SQL Injection Safe Batch.SQL Injection Safe Batch
Consider the following code:01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | import java.sql.Connection; import java.sql.PreparedStatement; //... String sql = "insert into employee (name, city, phone) values (?, ?, ?)" ; Connection connection = new getConnection(); PreparedStatement ps = connection.prepareStatement(sql); for (Employee employee: employees) { ps.setString( 1 , employee.getName()); ps.setString( 2 , employee.getCity()); ps.setString( 3 , employee.getPhone()); ps.addBatch(); } ps.executeBatch(); ps.close(); connection.close(); |
java.sql.PreparedStatement
and added insert query in the batch. This is the solution you must implement in your batch insert logic, instead of above Statement
one.Still there is one problem with this solution. Consider a scenario where you want to insert half million records into database using batch. Well, that may generate OutOfMemoryError:
1 2 3 4 | java.lang.OutOfMemoryError: Java heap space com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72) com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330) org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171) |
Smart Insert: Batch within Batch
This is a simplest solution. Consider a batch size like 1000 and insert queries in the batches of 1000 queries at a time.01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | String sql = "insert into employee (name, city, phone) values (?, ?, ?)" ; Connection connection = new getConnection(); PreparedStatement ps = connection.prepareStatement(sql); final int batchSize = 1000 ; int count = 0 ; for (Employee employee: employees) { ps.setString( 1 , employee.getName()); ps.setString( 2 , employee.getCity()); ps.setString( 3 , employee.getPhone()); ps.addBatch(); if (++count % batchSize == 0 ) { ps.executeBatch(); } } ps.executeBatch(); // insert remaining records ps.close(); connection.close(); |
count
and once it reaches batchSize
which is 1000, we call executeBatch()
.
No comments:
Post a Comment