java实现jdbc批量插入数据

 更新时间:2016年05月08日 19:56:00   投稿:lijiao  
这篇文章主要为大家详细介绍了java实现jdbc批量插入数据,三种JDBC批量插入编程方法进行比较,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

文章首先介绍三种JDBC批量插入编程方法,进行比较,具体内容如下

JDBC批量插入主要用于数据导入和日志记录因为日志一般都是先写在文件下的等。
我用Mysql 5.1.5的JDBC driver 分别对三种比较常用的方法做了测试

方法一:使用PreparedStatement加批量的方法

try { 
 Class.forName("com.mysql.jdbc.Driver"); 
 conn = DriverManager.getConnection(o_url, userName, password); 
 conn.setAutoCommit(false); 
 String sql = "INSERT adlogs(ip,website,yyyymmdd,hour,object_id) VALUES(?,?,?,?,?)"; 
 PreparedStatement prest = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY); 
 for(int x = 0; x < size; x++){ 
 prest.setString(1, "192.168.1.1"); 
 prest.setString(2, "localhost"); 
 prest.setString(3, "20081009"); 
 prest.setInt(4, 8); 
 prest.setString(5, "11111111"); 
 prest.addBatch(); 
 } 
 prest.executeBatch(); 
 conn.commit(); 
 conn.close(); 
} catch (SQLException ex) { 
 Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex); 
} catch (ClassNotFoundException ex) { 
 Logger.getLogger(MyLogger.class.getName()).log(Level.SEVERE, null, ex); 
} 

说明下在建Statement的时候,后面两个参数的意义:
第一个参数指定 ResultSet 的类型。其选项有:
TYPE_FORWARD_ONLY:缺省类型。只允许向前访问一次,并且不会受到其他用户对该数据库所作更改的影响。
TYPE_SCROLL_INSENSITIVE:允许在列表中向前或向后移动,甚至可以进行特定定位,例如移至列表中的第四个记录或者从当前位置向后移动两个记录。不会受到其他用户对该数据库所作更改的影响。
TYPE_SCROLL_SENSITIVE:象 TYPE_SCROLL_INSENSITIVE 一样,允许在记录中定位。这种类型受到其他用户所作更改的影响。如果用户在执行完查询之后删除一个记录,那个记录将从 ResultSet 中消失。类似的,对数据值的更改也将反映在 ResultSet 中。
第二个参数设置 ResultSet 的并发性,该参数确定是否可以更新 ResultSet。其选项有:
CONCUR_READ_ONLY:这是缺省值,指定不可以更新
ResultSet CONCUR_UPDATABLE:指定可以更新 ResultSet

方法二:使用Statement加批量的方法

conn.setAutoCommit(false); 
 Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); 
 for(int x = 0; x < size; x++){ 
 stmt.addBatch("INSERT INTO adlogs(ip,website,yyyymmdd,hour,object_id) VALUES('192.168.1.3', 'localhost','20081009',8,'23123')"); 
 } 
stmt.executeBatch(); 
conn.commit(); 

方法三:直接使用Statement

conn.setAutoCommit(false); 
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, 
   ResultSet.CONCUR_READ_ONLY); 
for(int x = 0; x < size; x++){ 
 stmt.execute("INSERT INTO adlogs(ip,website,yyyymmdd,hour,object_id) VALUES('192.168.1.3', 'localhost','20081009',8,'23123')"); 
} 
conn.commit(); 

使用上述方法分别插入10万条数据的平均测试时间为:
方法一:17.844s
方法二:18.421s
方法三:16.359s

可以看出JDBC的batch语句插入不但没有性能提升,反而比没有用batch的时候要慢,当然这可能跟JDBC具体驱动的实现方法有关。 附件中是我测试代码,可以用来在自己电脑上跑一下。

在执行批量插入的时候最主要的是将自动提交取消,这样不管是否用JDBC的batch语法应该都没有关系。
conn.setAutoCommit(false) 

个人觉得第一种方法是最方便最实用的。

jdbc批量插入数据 例子讲解:

最近做一个将excel数据导入数据库的程序时,由于数据量大,准备采用jdbc的批量插入。于是用了preparedStatement.addBatch();当加入1w条数据时,再执行插入操作,preparedStatement.executeBatch()。我原以为这样会很快,结果插入65536条数据一共花30多分钟,完全出乎我的意料。于是问了一下同事,他们在处理这种大批量数据导入的时候是如何处理的,发现他们也是用的jdbc批量插入处理,但与我不同是:他们使用了con.setAutoCommit(false);然后再preparedStatement.executeBatch()之后,再执行con.commit();于是再试,什么叫奇迹?就是刚刚导入这些数据花了半小时,而加了这两句话之后,现在只用了15秒钟就完成了。于是去查查了原因,在网上发现了如下一段说明:

    * When importing data into InnoDB, make sure that MySQL does not have autocommit mode enabled because that

      requires a log flush to disk for every insert. To disable autocommit during your import operation, surround it with

      SET autocommit and COMMIT statements:

      SET autocommit=0;
     ... SQL import statements ...
     COMMIT;

第一次,正是因为没有setAutoCommit(false);那么对于每一条insert语句,都会产生一条log写入磁盘,所以虽然设置了批量插入,但其效果就像单条插入一样,导致插入速度十分缓慢。

部分代码如下:

String sql = "insert into table *****";
con.setAutoCommit(false);
ps = con.prepareStatement(sql);
for(int i=1; i<65536; i++){
 ps.addBatch();
 // 1w条记录插入一次
 if (i % 10000 == 0){
 ps.executeBatch();
 con.commit();
 }
}
// 最后插入不足1w条的数据
ps.executeBatch();
con.commit();

以上只是小菜,下面接着“上菜”:

1、测试批量写入数据

 long start = System.currentTimeMillis();
 DaoRecord daoRecord = new DaoRecord();
 List<T> list = new ArrayList<T>();
 for(int i = 1; i <= 1000; i++){
 for(int j = 1; j <= 1000; j++){
 T t = new T();
 t.setI(i);
 t.setJ(j);
 list.add(t);
 }
 }
 daoRecord.InsertBatch(list);
 System.out.println("耗时:" + (System.currentTimeMillis()-start)+"毫秒");

2、批量写入数据测试

 public void InsertBatch(List<T> list){
 String sql = "insert into t(go,back) values(?,?)";
 DBHelper dbh = new DBHelper(sql);
 Connection conn = dbh.returnConn();
 try {
 conn.setAutoCommit(false);//注意此句一定要为false,原因见第一篇参考文献
 PreparedStatement ps = conn.prepareStatement(sql);
 for(int i = 0; i < list.size(); i++){
 ps.setInt(1, list.get(i).getI());
 ps.setInt(2, list.get(i).getJ());
 ps.addBatch();
 if (i % 10000 == 0){
  ps.executeBatch();
  conn.commit();
  }
 }
 ps.executeBatch();
 conn.commit();
 conn.close();
 } catch (SQLException e) {
 // TODO 自动生成的 catch 块
 e.printStackTrace();
 }
 }

数据表:

实验结果:

以上就是本文的全部内容,希望对大家的学习有所帮助。

相关文章

  • SpringBoot详细讲解静态资源导入的实现

    SpringBoot详细讲解静态资源导入的实现

    在Web开发过程中,我们需要接触许多静态资源,如CSS、JS、图片等;在之前的开发中,这些资源都放在Web目录下,用到的时候按照对应路径访问即可。不过在SpringBoot项目中,没有了Web目录,那这些静态资源该放到哪里去,又要如何访问呢?这就是我们要讲的静态资源导入
    2022-05-05
  • jdk8的datetime时间函数使用示例

    jdk8的datetime时间函数使用示例

    这篇文章主要介绍了jdk8的datetime时间函数使用示例,需要的朋友可以参考下
    2014-03-03
  • java集合进行排序的方式总结

    java集合进行排序的方式总结

    在本篇文章里小编给大家整理的是一篇关于java集合进行排序的两种方式总结,有兴趣的朋友们可以学习参考下。
    2021-08-08
  • java表单提交中文乱码的解决方法

    java表单提交中文乱码的解决方法

    这篇文章主要介绍了java表单提交中文乱码的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • java实现批量下载 多文件打包成zip格式下载

    java实现批量下载 多文件打包成zip格式下载

    这篇文章主要为大家详细介绍了java实现批量下载、将多文件打包成zip格式下载,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • Java中随机函数变换的示例详解

    Java中随机函数变换的示例详解

    这篇文章主要为大家详细介绍了Java中随机函数的变换,文中的示例代码讲解详细,对我们学习Java有一定的帮助,感兴趣的可以了解一下
    2022-08-08
  • java实现将ftp和http的文件直接传送到hdfs

    java实现将ftp和http的文件直接传送到hdfs

    前面几篇文章,我们已经做了很好的铺垫了,几个要用到的工具我们都做了出来,本文就是将他们集合起来,说下具体的用法,小伙伴们可以参考下。
    2015-03-03
  • 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    这篇文章主要介绍了Java多线程之内置锁(synchronized)和显式锁(ReentrantLock)的深入理解新的和用法,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • SpringBoot中@KafkaListener使用${}动态指定topic问题

    SpringBoot中@KafkaListener使用${}动态指定topic问题

    在SpringKafka中,使用${}引用Spring属性配置,可以在不同环境中重新配置topic名称,而无需修改代码,在application.properties或application.yml中定义topic名称,并在代码中使用${}引用
    2024-12-12
  • JDK8中Optional类巧用之判空操作

    JDK8中Optional类巧用之判空操作

    善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅,这篇文章主要给大家介绍了JDK8中Optional类巧用之判空的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-08-08

最新评论