使用PreparedStatement(方式一):
@Test
public void test1() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = DBUtil.getConnection();
String sql = "insert into table1(`name`) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 20000; i++) {
ps.setString(1, "name_" + i);
ps.execute();
}
long end = System.currentTimeMillis();
System.out.println("执行20000条sql共花费" + (end - start) + "毫秒");
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.CloseDB(conn, ps);
}
}
使用PreparedStatement相较于Statement在批量插入上的优点:不用每次都去编译sql语句。
使用PreparedStatement的方式二:使用了 addBatch() / executeBatch() / clearBatch()三板斧,batch类似缓冲池,可以先攒一定数量的sql,数量到了我们指定batch的大小然后再批量执行。代码如下:
/*
* 修改1: 使用 addBatch() / executeBatch() / clearBatch()
* 修改2:mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。
* ?rewriteBatchedStatements=true 写在配置文件的url后面
* 修改3:使用更新的mysql 驱动:mysql-connector-java-5.1.37-bin.jar
*
*/
@Test
public void test2() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = DBUtil.getConnection();
String sql = "insert into table1(`name`) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 10000000; i++) {
ps.setString(1, "name_" + i);
//ps.execute();
//1."攒"sql
ps.addBatch();
if (i % 500 == 0) {
//2.执行Batch
ps.executeBatch();
//3.清空Batch
ps.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println("执行一千万条sql共花费" + (end - start) + "毫秒");
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.CloseDB(conn, ps);
}
}
使用PreparedStatement的方式三:使用batch批量处理的前提下,设置手动提交,因为每次执行executeBatch会自动提交一次,这里也会涉及与数据库的交互,需要耗费一定的时间,因此我们可以设置手动提交,等执行完所有要批量插入的数据后在手动提交。代码如下:
@Test
public void test3() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = DBUtil.getConnection();
//设置为手动提交数据
conn.setAutoCommit(false);
String sql = "insert into table1(`name`) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 10000000; i++) {
ps.setString(1, "name_" + i);
//ps.execute();
//1.“攒”sql
ps.addBatch();
if (i % 500 == 0) {
//2.执行Batch
ps.executeBatch();
//3.清空Batch
ps.clearBatch();
}
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.println("执行一千万条sql共花费" + (end - start) + "毫秒");
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.CloseDB(conn, ps);
}
}
三种方式的效率依次递进,当然具体情况还是要分具体应用场景来看。
补充:
关于rewriteBatchedStatements这个参数介绍:
MySQL的JDBC连接的url中要加rewriteBatchedStatements参数,并保证5.1.13以上版本的驱动,才能实现高性能的批量插入。
MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。
只有把rewriteBatchedStatements参数置为true, 驱动才会帮你批量执行SQL。
另外这个选项对INSERT/UPDATE/DELETE都有效。
参考资料:
https://blog.csdn.net/weixin_45861045/article/details/126095061 使用PreparedStatement执行批量插入sql的三种方式以及效率
https://blog.csdn.net/qq_34283987/article/details/107694587 批处理 rewriteBatchedStatements=true