在尝试过SQLite批量插入一百万条记录,执行时长高达20多分钟后,就在想一个问题,这样的性能是不可能被广泛应用的,更不可能出现在真实的生产环境中,那么对此应该如何优化一下呢?
首先分析一下批量插入的逻辑
//循环插入100,0000条记录
for (int i = 0; i < 1000000; i++) {
//执行插入操作
rowsInserted = pstmt.executeUpdate();
}
//输出计时
上述代码创建一个循环,循环一百万次,每一次循环更新插入一条数据,这样一来就是对数据库操作了一百万次,虽然实现了批量操作,但是却对数据库造成了很大的开销,如果数据量再进一步扩大,此方法保不齐会让服务崩掉,所以这不是个最优解。
能不能对数据库只操作一次,就能实现数据的批量操作呢?
事务
我可以开启一个事务,把一百万次的循环插入放到一个批处理中,最后提交事务,这样一来只对数据库进行一次操作实现数据批量插入。
接下来设计代码:
import java.sql.*;
public class SQLiteBatchInsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//建立数据库连接
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection("jdbc:sqlite:D:\\env\\SQLite\\data\\user.db");
//设置手动提交事务
conn.setAutoCommit(false);
String tableName = "user";
// 准备SQL语句
String sql = "INSERT INTO " + tableName + " (name, age) VALUES (?,?)";
pstmt = conn.prepareStatement(sql);
//批量添加数据
for (int i = 0; i < 1000000; i++) {
pstmt.setString(1, "王五");
pstmt.setString(2, "25");
pstmt.addBatch();
}
// 记录执行开始时间
double startTime = System.currentTimeMillis();
//执行批处理
pstmt.executeBatch();
//提交事务
conn.commit();
//记录执行结束时间
double endTime = System.currentTimeMillis();
double duration = endTime - startTime;
System.out.println("Batch insert successful!");
System.out.println("执行时间为:"+duration/1000+"s");
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
if (conn != null) {
try {
//如果出现异常,回滚事务
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
} finally {
//关闭资源
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
运行后发现,执行时间惊人的只有 1s 左右
为了验证这一结果,我不得不去数据库里查一下,果不其然插入成功
看来,SQLite 利用事务执行批量操作完全是个可行的方案,大大的降低了对数据库的开销,极大的减少了执行时间,效率有了质的提升。