今天自己在家准备面试内容,写了个java使用多线程往mysql数据库插入数据的例子:
总结:
不管数据库引擎是MYISAM还是InnoDB,情况都是
没有线程池的情况下就不说了,一直创建数据库连接一会就出错了,基本对于上万条的数据插入不可用。
使用线程池,开启多个线程并发执行的效率是明显高于单线程的插入的,所以对于大数据量数据迁移的情况下使用并发线程池还是很能提高效率的。
小弟新手,有什么错误还请指明,谢谢。
以下是测试内容:
表结构:
表引擎:MyISAM
程序代码:
自己写了个简单的线程池,在使用线程池之前插入一万条数据的时间是(并发没有线程池:所有线程执行完毕:16663),没写线程池之前的代码就不上传了,就是简单的jdbc连接,下面是使用线程池的代码:
JdbcUtils.java
package com.inserttestdata; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Vector; public class JdbcUtils { static String driver = "com.mysql.jdbc.Driver"; static String url="jdbc:mysql://localhost:3306/test"; static String user="root"; static String pwd = "123456"; static Vector<Connection> pools = new Vector<Connection>(); public static Connection getDBConnection(){ try { //1.加载驱动 Class.forName(driver); //2.取得数据库连接 Connection conn = DriverManager.getConnection(url, user, pwd); return conn; } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } static { int i = 0; while(i<10){ pools.add(getDBConnection()); i++; } } public static synchronized Connection getPool(){ if(pools != null && pools.size() > 0){ int last_ind = pools.size() -1; return pools.remove(last_ind); }else{ return getDBConnection(); } } public static int insert(String sql,Object[] params){ Connection conn = getPool(); PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); for(int i=0;i<params.length;i++){ pstmt.setObject(i+1, params[i]); } return pstmt.executeUpdate(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(pstmt != null){ try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ // conn.close(); pools.add(conn); } } return 0; } }
测试类的代码:
doInsert.java
package com.inserttestdata; import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class doInsert { public static void main(String[] args) { long startTimes = System.currentTimeMillis(); String[] names = new String[]{"LXL","MQJ","JOE","JON","JACK","LILY","LUCY","NOB","FDSE","GTX"}; int threadCount = 10; int total = 100000; int every = total/threadCount; final CountDownLatch latch = new CountDownLatch(threadCount); // ExecutorService executor = Executors.newFixedThreadPool(10); for(int i=0;i<threadCount;i++){ new Thread(new Worker(latch,names[i],i*every,(i+1)*every)).start(); } try { latch.await(); long endTimes = System.currentTimeMillis(); System.out.println("所有线程执行完毕:" + (endTimes - startTimes)); } catch (InterruptedException e) { e.printStackTrace(); } } } class Worker implements Runnable{ static String sql = "INSERT INTO `tb_demo` (`name`,cre_date) VALUES (?, ?);"; int start = 0; int end = 0; String name = ""; CountDownLatch latch; public Worker(CountDownLatch latch,String name, int start,int end){ this.start = start; this.end = end; this.name = name; this.latch = latch; } @Override public void run() { for (int i = start; i < end; i++) { System.out.println("线程" + Thread.currentThread().getName()+ "正在执行。。"); Object[] params = new Object[] { name + i, new Date() }; JdbcUtils.insert(sql, params); } latch.countDown(); } }
使用线程池并且开启10个线程插入十万条数据的时间是:
下面是使用线程池但只有一个线程的情况下的测试时间:
只需要将main函数中的int threadCount = 10;改为int threadCount = 1;就可以了,
测试结果:
(MYISAM)并发没有线程池:所有线程执行完毕:16663ms
(MYISAM)并发使用线程池:所有线程执行完毕:4194ms
(MYISAM)单线程使用线程池:所有线程执行完毕:14667ms
将表的引擎改为InnoDB后测试10000条数据的插入操作:
(InnoDB)并发使用线程池:所有线程执行完毕:74968ms
(InnoDB)单线程使用线程池:所有线程执行完毕:481712ms
总结:
不管数据库引擎是MYISAM还是InnoDB,情况都是:
没有线程池的情况下就不说了,一直创建数据库连接一会就出错了,基本对于上万条的数据插入不可用。
使用线程池,开启多个线程并发执行的效率是明显高于单线程的插入的,所以对于大数据量数据迁移的情况下使用并发线程池还是很能提高效率的。
小弟新手,有什么错误还请指明,谢谢。
另外我今天搜到一个这样的结果,是我理解的错了还是他的回答错了呢,求证一下:
http://zhidao.baidu.com/link?url=XMyaFELOmEIkkEAeNZWfgJKM8jTinhimX8vzwXaXcRiTcvD_YzWVm6jW923Ev2wmOPaUL0EfxyWRXhwccoQMaq
内容如下: