处理千万级数据量的入库需要考虑性能、稳定性和可扩展性。以下是一些策略和步骤,用于有效地将大量数据插入数据库:
1. 数据库设计优化
- 分表策略:如果可能,通过分表(水平分割)来分散数据量,减少单表的压力。
- 索引优化:确保只有必要的列上有索引,避免在非索引列上进行大量插入操作。
2. 使用PreparedStatement
- 预编译SQL:使用
PreparedStatement
来预编译SQL语句,减少数据库编译SQL的时间。 - 批量插入:利用
addBatch()
和executeBatch()
进行批量插入,减少数据库交互次数。
3. 多线程处理
- 线程池:使用线程池来管理多个插入任务,提高资源利用率和响应速度。
- 任务分配:将数据集分割成多个批次,每个批次由不同的线程或线程池中的工作线程处理。
4. 事务管理
- 批量提交:在每个批次的数据插入完毕后,使用事务提交来确保数据的一致性。
- 避免锁竞争:合理设计事务大小和隔离级别,以减少锁竞争和死锁的可能性。
5. 异步处理
- 异步写入:如果实时性要求不高,可以使用消息队列等异步机制先缓存数据,后批量处理。
6. 硬件和配置
- 增加资源:根据需要增加服务器的CPU、内存或存储资源。
- 数据库配置:调整数据库配置,如连接池大小、缓冲区大小等。
7. 监控和日志
- 性能监控:监控数据库的性能指标,如响应时间、吞吐量等。
- 日志记录:记录操作日志,用于问题排查和性能分析。
8. 代码示例
以下是一个简化的Java代码示例,展示如何使用PreparedStatement
和多线程进行批量数据插入:
import java.sql.*;
import java.util.concurrent.*;
public class MassiveInsertExample {
static final String INSERT_SQL = "insert into TR_BASE_PARAM_TYPE(c_type_code,c_type_name,c_leaf,c_parent_code,c_type_class)values (SEQ_RISK_BASE_PARAM_TYPE_CODE.NEXTVAL,?,?,?,?)";
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
Connection connection = establishConnection();
// 假设dataList包含千万级数据
List<List<BaseParamTypePO >> partitionedData = partitionData(); // 每批10000条数据
for (List<BaseParamTypePO > batch : partitionedData) {
executor.submit(new InsertTask(connection, batch));
}
executor.shutdown();
}
static class InsertTask implements Runnable {
private final Connection connection;
private final List<BaseParamTypePO > batch;
InsertTask(Connection connection, List<BaseParamTypePO > batch) {
this.connection = connection;
this.batch = batch;
}
@Override
public void run() {
try (PreparedStatement stmt = connection.prepareStatement(INSERT_SQL)) {
connection.setAutoCommit(false);
for (BaseParamTypePO data : batch) {
stmt.setString(1, data.col1);
stmt.addBatch();
}
stmt.executeBatch();
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 数据库连接建立
static Connection establishConnection() {
// 实现数据库连接逻辑
Connection conn = null;
try {
//1、注册驱动
Class.forName("oracle.jdbc.OracleDriver");
//2、获取连接
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521/orcl","ROOT","123456");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return conn;
}
// 数据分割逻辑
static List<List<Data>> partitionData(List<Data> dataList, int batchSize) {
// 实现数据分割逻辑
BaseParamTypePO baseParamSettingPO = new BaseParamTypePO();
baseParamSettingPO.setParentCode("1");
baseParamSettingPO.setTypeClass("1");
baseParamSettingPO.setTypeName("测试");
baseParamSettingPO.setLeaf(true);
List<BaseParamTypePO> baseParamTypePOS = new ArrayList<>();
List<List<BaseParamTypePO>> baseParamList = new ArrayList<>();
for (int j = 0; j < 10000; j++) {
baseParamTypePOS.add(baseParamSettingPO);
}
for (int j = 0; j < 1000; j++) {
baseParamList.add(baseParamTypePOS);
}
return baseParamList;
}
// 数据对象
@Getter
@Setter
@ToString
static class BaseParamTypePO {
private String typeCode;
private String typeName;
private boolean leaf;
private String parentCode;
private String typeClass;
}
}
注意事项
- 在实际应用中,需要根据具体的业务场景和数据库特性进行调整。
- 确保在进行大量数据操作时,数据库的备份和恢复策略是可靠的。
- 考虑到可能的失败情况,实现重试机制或错误数据处理策略。