上一篇
java中怎么实现大批量插入数据
- 后端开发
- 2025-07-29
- 2
Java中实现大批量插入数据,可以使用JDBC的
addBatch()
和
executeBatch()
方法。
Java中实现大批量插入数据是一项常见的任务,尤其是在处理大量数据时,为了提高性能和效率,通常需要采用一些优化策略和技术,以下是几种常见的方法及其详细实现步骤:
使用JDBC的批量插入
步骤:
- 获取数据库连接:使用
DriverManager.getConnection()
获取数据库连接。 - 关闭自动提交:通过
connection.setAutoCommit(false)
关闭自动提交模式。 - 准备SQL语句:使用
PreparedStatement
预编译SQL语句。 - 添加批处理:使用
preparedStatement.addBatch()
将多条插入语句添加到批处理中。 - 执行批处理:调用
preparedStatement.executeBatch()
执行批处理。 - 提交事务:通过
connection.commit()
提交事务。 - 处理异常:捕获并处理可能的
SQLException
,并在必要时回滚事务。
示例代码:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class BatchInsertExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydatabase"; String user = "username"; String password = "password"; try (Connection connection = DriverManager.getConnection(url, user, password)) { connection.setAutoCommit(false); String sql = "INSERT INTO my_table (column1, column2) VALUES (?, ?)"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { for (int i = 0; i < 1000; i++) { preparedStatement.setString(1, "value1_" + i); preparedStatement.setString(2, "value2_" + i); preparedStatement.addBatch(); if (i % 100 == 0) { // 每100条执行一次批处理 preparedStatement.executeBatch(); connection.commit(); } } preparedStatement.executeBatch(); // 执行剩余的批处理 connection.commit(); } catch (SQLException e) { connection.rollback(); e.printStackTrace(); } } catch (SQLException e) { e.printStackTrace(); } } }
使用Hibernate的批量插入
步骤:
- 配置Hibernate:设置
hibernate.jdbc.batch_size
属性以启用批量插入。 - 开启事务:使用
Session.beginTransaction()
开启事务。 - 批量插入数据:通过
Session.save()
或Session.persist()
方法插入数据,并定期调用Session.flush()
和Session.clear()
以清空缓存。 - 提交事务:调用
transaction.commit()
提交事务。
示例代码:
import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class HibernateBatchInsertExample { public static void main(String[] args) { Session session = new Configuration().configure().buildSessionFactory().openSession(); Transaction transaction = session.beginTransaction(); try { for (int i = 0; i < 1000; i++) { MyEntity entity = new MyEntity("value1_" + i, "value2_" + i); session.save(entity); if (i % 100 == 0) { // 每100条执行一次批处理 session.flush(); session.clear(); } } transaction.commit(); } catch (Exception e) { transaction.rollback(); e.printStackTrace(); } finally { session.close(); } } }
使用Spring JdbcTemplate的批量插入
步骤:
- 配置JdbcTemplate:在Spring配置文件中配置
JdbcTemplate
。 - 准备数据:将数据组织成
List<Object[]>
或List<Map<String, Object>>
。 - 批量插入:使用
JdbcTemplate.batchUpdate()
方法执行批量插入。
示例代码:
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; import java.util.ArrayList; import java.util.List; public class SpringBatchInsertExample { public static void main(String[] args) { DataSource dataSource = new DriverManagerDataSource("jdbc:mysql://localhost:3306/mydatabase", "username", "password"); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String sql = "INSERT INTO my_table (column1, column2) VALUES (?, ?)"; List<Object[]> batchArgs = new ArrayList<>(); for (int i = 0; i < 1000; i++) { batchArgs.add(new Object[]{"value1_" + i, "value2_" + i}); } jdbcTemplate.batchUpdate(sql, batchArgs); } }
使用多线程并行插入
步骤:
- 分割数据:将大批量数据分割成多个小批次。
- 创建线程池:使用
ExecutorService
创建线程池。 - 并行插入:为每个小批次数据创建一个任务,并行执行插入操作。
- 等待完成:使用
Future
或CountDownLatch
等待所有任务完成。
示例代码:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class MultiThreadBatchInsertExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydatabase"; String user = "username"; String password = "password"; int batchSize = 100; int totalRecords = 1000; int threadCount = 10; ExecutorService executorService = Executors.newFixedThreadPool(threadCount); for (int i = 0; i < totalRecords; i += batchSize) { int start = i; int end = Math.min(i + batchSize, totalRecords); executorService.submit(() -> { try (Connection connection = DriverManager.getConnection(url, user, password)) { connection.setAutoCommit(false); String sql = "INSERT INTO my_table (column1, column2) VALUES (?, ?)"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { for (int j = start; j < end; j++) { preparedStatement.setString(1, "value1_" + j); preparedStatement.setString(2, "value2_" + j); preparedStatement.addBatch(); } preparedStatement.executeBatch(); connection.commit(); } catch (SQLException e) { connection.rollback(); e.printStackTrace(); } } catch (SQLException e) { e.printStackTrace(); } }); } executorService.shutdown(); try { executorService.awaitTermination(1, TimeUnit.HOURS); } catch (InterruptedException e) { e.printStackTrace(); } } }
使用存储过程进行批量插入
步骤:
- 编写存储过程:在数据库中编写一个存储过程,接受批量数据作为参数。
- 调用存储过程:在Java中使用
CallableStatement
调用存储过程。 - 传递数据:将批量数据传递给存储过程。
- 执行存储过程:调用
CallableStatement.execute()
执行存储过程。
示例代码:
import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.List; import java.util.Arrays; public class StoredProcedureBatchInsertExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydatabase"; String user = "username"; String password = "password"; List<String[]> data = Arrays.asList( new String[]{"value1_1", "value2_1"}, new String[]{"value1_2", "value2_2"}, // 添加更多数据... ); try (Connection connection = DriverManager.getConnection(url, user, password)) { String sql = "{CALL BatchInsertProcedure(?, ?)}"; try (CallableStatement callableStatement = connection.prepareCall(sql)) { for (String[] record : data) { callableStatement.setString(1, record[0]); callableStatement.setString(2, record[1]); callableStatement.addBatch(); } callableStatement.executeBatch(); } } catch (SQLException e) { e.printStackTrace(); } } }
FAQs
Q1: 为什么在大批量插入时需要关闭自动提交?
A1: 关闭自动提交可以显著提高性能,因为每次插入操作不需要立即提交事务,减少了磁盘I/O操作,通过手动控制事务,可以在一批插入完成后一次性提交,从而减少事务管理的开销。
Q2: 在使用多线程并行插入时,如何避免数据冲突和锁争用?
A2: 为了避免数据冲突和锁争用,可以将数据分割成多个独立的小批次,并为每个批次分配一个独立的线程进行处理。