上一篇
java中怎么实现大批量插入数据
- 后端开发
- 2025-07-29
- 4503
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: 为了避免数据冲突和锁争用,可以将数据分割成多个独立的小批次,并为每个批次分配一个独立的线程进行处理。
