多线程往Oracle数据库里插入数据的优化

昨 天做了一个东西,要实现解析txt文件,然后入库的功能。开始试验了一下单线程插入,速度实在太慢了,半个小时才插入了2W多条数据,后来改用Java的 线程池启用了30个线程,并发的执行,插入100W条数据用了一个多小时。后来又对业务层的事务做了一些调整,每1000条insert之后才提交一次, 一共开了20个线程,最后100W条数据入库一共用了14分钟不到,平均一分钟7.1W条左右。 代码如下:
  1. /**
  2. * 分析Apache日志的定时任务.每天运行数次.
  3. *
  4. * @author Along
  5. *
  6. * @version $Revision$
  7. *
  8. * @since 2009-2-9
  9. */
  10. public class ApacheLogAnalysisTask {
  11.         /**
  12.          * Logger for this class
  13.          */
  14.         private static final Log logger = LogFactory.getLog(ApacheLogAnalysisTask.class);
  15.        
  16.         //总线程数
  17.         private static final int THREAD_COUNT = 20;
  18.        
  19.         //每个线程插入的日志数
  20.         private static final long LOG_COUNT_PER_THREAD = 1000;
  21.        
  22.         //日志文件的位置
  23.         private static final String LOG_FILE = Property.LOG_FILE_PATH + "formatLog.txt";
  24.        
  25.         private IObjectActionDetailService objectActionDetailService;
  26.        

  27.         public void setObjectActionDetailService(IObjectActionDetailService objectActionDetailService) {
  28.                 this.objectActionDetailService = objectActionDetailService;
  29.         }

  30.         public void execute() {
  31.                 this.multiAnalysisLog();
  32.         }
  33.        
  34.         private void multiAnalysisLog() {
  35.                 ExecutorService exePool = Executors.newFixedThreadPool(THREAD_COUNT);
  36.                
  37.                 FileReader fr = null;
  38.                 BufferedReader br = null;
  39.                 long beginLine = 1;
  40.                 long endLine = 0;
  41.                 String logFileBack = Property.LOG_FILE_PATH + "/formatLog_" + DateUtil.getSystemCurrentDate() + "_" + System.currentTimeMillis() + ".txt";
  42.                
  43.                 try {
  44.                         //文件拷贝出来一个新的,并将原先的删除.
  45.                         FileUtil.copyfile(LOG_FILE, logFileBack, true);
  46.                         FileUtil.deleteFile(LOG_FILE);
  47.                         System.out.println(logFileBack);
  48.                        
  49.                         fr = new FileReader(logFileBack);
  50.                         br = new BufferedReader(fr);
  51.                        
  52.                         while ((br.readLine()) != null){
  53.                                 endLine++;
  54.                                
  55.                                 //每个线程分配固定的行数
  56.                                 if((endLine - beginLine + 1) == LOG_COUNT_PER_THREAD) {
  57.                                         exePool.execute(new AnalysisLogTask(logFileBack, beginLine, endLine));
  58.                                         beginLine = endLine + 1;
  59.                                 }
  60.                         }
  61.                        
  62.                         //最后一个线程
  63.                         if (endLine > beginLine) {
  64.                                 exePool.execute(new AnalysisLogTask(logFileBack, beginLine, endLine));
  65.                         }

  66.                 } catch (FileNotFoundException e) {
  67.                         e.printStackTrace();
  68.                 } catch (IOException e) {
  69.                         e.printStackTrace();
  70.                 } finally {
  71.                         if (br != null) {
  72.                                 try {
  73.                                         br.close();
  74.                                         br = null;
  75.                                 } catch (IOException e) {
  76.                                         if (logger.isErrorEnabled()) {
  77.                                                 logger.error("run()", e);
  78.                                         }

  79.                                         e.printStackTrace();
  80.                                 }
  81.                         }
  82.                        
  83.                         if (fr != null) {
  84.                                 try {
  85.                                         fr.close();
  86.                                         fr = null;
  87.                                 } catch (IOException e) {
  88.                                         if (logger.isErrorEnabled()) {
  89.                                                 logger.error("run()", e);
  90.                                         }

  91.                                         e.printStackTrace();
  92.                                 }
  93.                         }
  94.                        
  95.                         exePool.shutdown();
  96.                         while (true) {
  97.                                 if (exePool.isTerminated()) {
  98.                                         System.out.println("ShutDown");
  99.                                         FileUtil.deleteFile(logFileBack);
  100.                                         break;
  101.                                 }
  102.                         }
  103.                        
  104.                 }
  105.         }
  106.        
  107.         private class AnalysisLogTask implements Runnable {
  108.                 //起始行
  109.                 private long beginLine;
  110.                
  111.                 //结束行
  112.                 private long endLine;
  113.                
  114.                 private String logFilePath;

  115.                 public AnalysisLogTask(String logFilePath, long beginLine, long endLine) {
  116.                         super();
  117.                         this.logFilePath = logFilePath;
  118.                         this.beginLine = beginLine;
  119.                         this.endLine = endLine;
  120.                 }

  121.                 @Override
  122.                 public void run() {
  123.                         FileReader fr = null;
  124.                         BufferedReader br = null;
  125.                         String tempStr = null;
  126.                         String[] tempArray = null;
  127.                         long currentLine = 0;
  128.                         List resultList = new ArrayList();
  129.                        
  130.                         ObjectActionDetail tempObjectActionDetailVO = null;
  131.                         try {
  132.                                 fr = new FileReader(logFilePath);
  133.                                 br = new BufferedReader(fr);
  134.                                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  135.                                
  136.                                 //跳过前置的行数
  137.                                 if (beginLine != 1) {
  138.                                         while ((currentLine < (beginLine-1)) && br.readLine() != null) {
  139.                                                 ++currentLine;
  140.                                         }
  141.                                 }
  142.                                
  143.                                 while ((tempStr = br.readLine()) != null && currentLine++ < endLine) {
  144.                                         tempArray = tempStr.split("\t");
  145.                                         tempObjectActionDetailVO = new ObjectActionDetail();

  146.                                         tempObjectActionDetailVO.setIp(tempArray[0]);
  147.                                         tempObjectActionDetailVO.setActionTime(sdf.parse(tempArray[1]));
  148.                                         tempObjectActionDetailVO.setSrcObjTypeId(Integer.parseInt(tempArray[2]));
  149.                                         tempObjectActionDetailVO.setSrcObjId(Integer.parseInt(tempArray[3]));
  150.                                         tempObjectActionDetailVO.setTarObjTypeId(Integer.parseInt(tempArray[4]));
  151.                                         tempObjectActionDetailVO.setTarObjId(Integer.parseInt(tempArray[5]));
  152.                                         tempObjectActionDetailVO.setActionId(Integer.parseInt(tempArray[6]));
  153.                                        
  154.                                         tempObjectActionDetailVO.setScore(0);
  155.                                         tempObjectActionDetailVO.setStatus(1);
  156.                                        
  157.                                         resultList.add(tempObjectActionDetailVO);
  158.                                 }
  159.                                
  160.                                 logger.info("Thread:" + Thread.currentThread().getName() + "   beginLine=" + beginLine + "   endLine=" + endLine);
  161.                                
  162.                                 objectActionDetailService.insertObjectActionDetailBatch(resultList);
  163.                         } catch (FileNotFoundException e) {
  164.                                 if (logger.isErrorEnabled()) {
  165.                                         logger.error("run()", e);
  166.                                 }

  167.                                 e.printStackTrace();
  168.                         } catch (IOException e) {
  169.                                 if (logger.isErrorEnabled()) {
  170.                                         logger.error("run()", e);
  171.                                 }

  172.                                 e.printStackTrace();
  173.                         } catch (ParseException e) {
  174.                                 if (logger.isErrorEnabled()) {
  175.                                         logger.error("run()", e);
  176.                                 }

  177.                                 e.printStackTrace();
  178.                         } finally {
  179.                                 if (br != null) {
  180.                                         try {
  181.                                                 br.close();
  182.                                                 br = null;
  183.                                         } catch (IOException e) {
  184.                                                 if (logger.isErrorEnabled()) {
  185.                                                         logger.error("run()", e);
  186.                                                 }

  187.                                                 e.printStackTrace();
  188.                                         }
  189.                                 }
  190.                                
  191.                                 if (fr != null) {
  192.                                         try {
  193.                                                 fr.close();
  194.                                                 fr = null;
  195.                                         } catch (IOException e) {
  196.                                                 if (logger.isErrorEnabled()) {
  197.                                                         logger.error("run()", e);
  198.                                                 }

  199.                                                 e.printStackTrace();
  200.                                         }
  201.                                 }
  202.                         }
  203.                 }
  204.         }
  205. }

今天又试验了一下先将整个文件拆分成小的单个文件,然后每个线程再解析自己的文件。测试后感觉这样的效果不好,明显不如多线程从一个文章读数据好,27分钟插入了100W条数据,平均一分钟3.7W条左右。怀疑是多线程读取文件,本地磁盘的I/O受限导致性能低下。 代码如下:

  1. /**
  2. * 分析Apache日志的定时任务.每天运行数次.
  3. *
  4. * @author Along
  5. *
  6. * @version $Revision$
  7. *
  8. * @since 2009-2-9
  9. */
  10. public class ApacheLogAnalysisTask {
  11.         /**
  12.          * Logger for this class
  13.          */
  14.         private static final Log logger = LogFactory.getLog(ApacheLogAnalysisTask.class);
  15.        
  16.         //总线程数
  17.         private static final int THREAD_COUNT = 10;
  18.        
  19.         //每个线程插入的日志数
  20.         private static final long LOG_COUNT_PER_THREAD = 3000;
  21.        
  22.         //日志文件的位置
  23.         private static final String LOG_FILE = Property.LOG_FILE_PATH + "/formatLog.txt";
  24.        
  25.         private IObjectActionDetailService objectActionDetailService;
  26.        

  27.         public void setObjectActionDetailService(IObjectActionDetailService objectActionDetailService) {
  28.                 this.objectActionDetailService = objectActionDetailService;
  29.         }

  30.         public void execute() {
  31.                 this.multiAnalysisLog();
  32.         }
  33.        
  34.         private void multiAnalysisLog() {
  35.                 ExecutorService exePool = Executors.newFixedThreadPool(THREAD_COUNT);
  36.                
  37.                 FileReader fr = null;
  38.                 FileWriter fw = null;
  39.                 BufferedReader br = null;
  40.                 int threadCount = 0;
  41.                 long tempLineCount = 0;
  42.                 String tempReadLineStr = null;
  43.                 long now = System.currentTimeMillis();
  44.                 String logFileBackFile = Property.LOG_FILE_PATH + "/old/formatLog_" + DateUtil.getSystemCurrentDate() + "_" + now + ".txt";
  45.                 String logFilePerThreadName = Property.LOG_FILE_PATH + "/old/formatLog_" + DateUtil.getSystemCurrentDate() + "_" + now;
  46.                
  47.                 try {
  48.                         //文件拷贝出来一个新的,并将原先的删除.
  49.                         FileUtil.copyfile(LOG_FILE, logFileBackFile, true);
  50.                         //FileUtil.deleteFile(LOG_FILE);
  51.                        
  52.                         fr = new FileReader(logFileBackFile);
  53.                         br = new BufferedReader(fr);
  54.                         fw = new FileWriter(logFilePerThreadName + "_" + ++threadCount + ".txt");
  55.                        
  56.                         while ((tempReadLineStr = br.readLine()) != null){
  57.                                 tempLineCount++;
  58.                                 fw.append(tempReadLineStr).append("\r\n");
  59.                                
  60.                                 //每个线程分配固定的行数
  61.                                 if(tempLineCount == LOG_COUNT_PER_THREAD) {
  62.                                         fw.flush();
  63.                                         fw.close();
  64.                                         exePool.execute(new AnalysisLogTask(logFilePerThreadName + "_" + threadCount + ".txt"));

  65.                                         //创建新的文件,临时变量清零.
  66.                                         fw = new FileWriter(logFilePerThreadName + "_" + ++threadCount + ".txt");
  67.                                         tempLineCount = 0;
  68.                                 }
  69.                         }
  70.                        
  71.                         //最后一个线程有文件则写入执行,没有,则删除最后一个建立的文件.
  72.                         if (tempLineCount != 0) {
  73.                                 fw.flush();
  74.                                 fw.close();
  75.                                 exePool.execute(new AnalysisLogTask(logFilePerThreadName + "_" + threadCount + ".txt"));
  76.                         } else {
  77.                                 fw.flush();
  78.                                 fw.close();
  79.                                
  80.                                 FileUtil.deleteFile(logFilePerThreadName + "_" + threadCount + ".txt");
  81.                         }

  82.                 } catch (FileNotFoundException e) {
  83.                         e.printStackTrace();
  84.                 } catch (IOException e) {
  85.                         e.printStackTrace();
  86.                 } finally {
  87.                         if (br != null) {
  88.                                 try {
  89.                                         br.close();
  90.                                         br = null;
  91.                                 } catch (IOException e) {
  92.                                         if (logger.isErrorEnabled()) {
  93.                                                 logger.error("run()", e);
  94.                                         }

  95.                                         e.printStackTrace();
  96.                                 }
  97.                         }
  98.                        
  99.                         if (fr != null) {
  100.                                 try {
  101.                                         fr.close();
  102.                                         fr = null;
  103.                                 } catch (IOException e) {
  104.                                         if (logger.isErrorEnabled()) {
  105.                                                 logger.error("run()", e);
  106.                                         }

  107.                                         e.printStackTrace();
  108.                                 }
  109.                         }
  110.                        
  111.                         FileUtil.deleteFile(logFileBackFile);
  112.                         logger.info("File has deleted:" + logFileBackFile);
  113.                        
  114.                         exePool.shutdown();
  115.                         //判断是不是所有的任务都执行完毕,执行完删除日志文件.
  116.                         while (true) {
  117.                                 if (exePool.isTerminated()) {
  118.                                         logger.info("All task has shutdown.");
  119.                                         break;
  120.                                 }
  121.                         }
  122.                        
  123.                 }
  124.         }
  125.        
  126.         private class AnalysisLogTask implements Runnable {

  127.                 //每个线程要处理的日志文件
  128.                 private String logFilePath;

  129.                 public AnalysisLogTask(String logFilePath) {
  130.                         super();
  131.                         this.logFilePath = logFilePath;
  132.                 }

  133.                 @Override
  134.                 public void run() {
  135.                         logger.info("Thread:" + Thread.currentThread().getName() + " running.");
  136.                        
  137.                         FileReader fr = null;
  138.                         BufferedReader br = null;
  139.                         String tempStr = null;
  140.                         String[] tempArray = null;
  141.                         List resultList = new ArrayList();
  142.                        
  143.                         ObjectActionDetail tempObjectActionDetailVO = null;
  144.                         try {
  145.                                 fr = new FileReader(logFilePath);
  146.                                 br = new BufferedReader(fr);
  147.                                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  148.                                
  149.                                 while ((tempStr = br.readLine()) != null) {
  150.                                         tempArray = tempStr.split("\t");
  151.                                         tempObjectActionDetailVO = new ObjectActionDetail();

  152.                                         tempObjectActionDetailVO.setIp(tempArray[0]);
  153.                                         tempObjectActionDetailVO.setActionTime(sdf.parse(tempArray[1]));
  154.                                         tempObjectActionDetailVO.setSrcObjTypeId(Integer.parseInt(tempArray[2]));
  155.                                         tempObjectActionDetailVO.setSrcObjId(Integer.parseInt(tempArray[3]));
  156.                                         tempObjectActionDetailVO.setTarObjTypeId(Integer.parseInt(tempArray[4]));
  157.                                         tempObjectActionDetailVO.setTarObjId(Integer.parseInt(tempArray[5]));
  158.                                         tempObjectActionDetailVO.setActionId(Integer.parseInt(tempArray[6]));
  159.                                        
  160.                                         tempObjectActionDetailVO.setScore(0);
  161.                                         tempObjectActionDetailVO.setStatus(1);
  162.                                        
  163.                                         resultList.add(tempObjectActionDetailVO);
  164.                                 }
  165.                                 objectActionDetailService.insertObjectActionDetailBatch(resultList);
  166.                         } catch (FileNotFoundException e) {
  167.                                 if (logger.isErrorEnabled()) {
  168.                                         logger.error("run()", e);
  169.                                 }

  170.                                 e.printStackTrace();
  171.                         } catch (IOException e) {
  172.                                 if (logger.isErrorEnabled()) {
  173.                                         logger.error("run()", e);
  174.                                 }

  175.                                 e.printStackTrace();
  176.                         } catch (ParseException e) {
  177.                                 if (logger.isErrorEnabled()) {
  178.                                         logger.error("run()", e);
  179.                                 }

  180.                                 e.printStackTrace();
  181.                         } finally {
  182.                                 if (br != null) {
  183.                                         try {
  184.                                                 br.close();
  185.                                                 br = null;
  186.                                         } catch (IOException e) {
  187.                                                 if (logger.isErrorEnabled()) {
  188.                                                         logger.error("run()", e);
  189.                                                 }

  190.                                                 e.printStackTrace();
  191.                                         }
  192.                                 }
  193.                                
  194.                                 if (fr != null) {
  195.                                         try {
  196.                                                 fr.close();
  197.                                                 fr = null;
  198.                                         } catch (IOException e) {
  199.                                                 if (logger.isErrorEnabled()) {
  200.                                                         logger.error("run()", e);
  201.                                                 }

  202.                                                 e.printStackTrace();
  203.                                         }
  204.                                 }
  205.                                
  206.                                 //删除本线程负责的日志文件
  207.                                 FileUtil.deleteFile(logFilePath);
  208.                                 logger.info("Thread:" + Thread.currentThread().getName() + "   logFilePath has deleted:" + logFilePath);
  209.                                 logger.info("Thread:" + Thread.currentThread().getName() + " shutdown.");
  210.                         }
  211.                 }
  212.         }
  213. }

后来又找系统管理员优化了一下网络,现在数据入库的速度是100W条7分钟 。相信应用和数据库移动到生产环境中,性能会进一步提升。

你可能感兴趣的:(BUG解决备忘录)