概述

     最近公司一.NET项目需要对其日志Log入数据库统计,写这个脚本导入的任务便落到我身上了。采用了熟练的Java,这个日志也不是很大,一个文件大概几兆,有上万条数据,一天大概有7,8个文件需要这样的导入处理。由于之前写Web没有这么去批处理这么多数据,所以没有太注意性能,第一个版本程序导入速度慢的吓人,一个文件导完可能需要10多分钟,也就是说如果把每天的文件导完可能需要2个多小时的时间,听听就很蛋疼,最终经过优化后,一个文件导入也就几秒,甚至可以更短。目标日志文件的信息都是按行存储,所以程序中按行读取后,然后进行相应的字符串截取入库。下面则为思路分享以及主要代码的分享。
 
优化思路
     1.程序流程:
       程序先读取本地的文件到内存,然后把内存的数据批量Insert到数据库。
     2.归纳:
     可以看出首先程序需要进行文件IO操作,然后则是数据JDBC操作,所以优化方向大致可以是以下几个:
          a.文件IO优化
          b.JDBC操作优化
          c.使用多线程并行JDBC操作
 文件常见IO简介
     Java的文件读写操作大概有这么几种方式,但是我们应该注意几种文件操作方式的区别,哪些操作方式适合不同的数据文件对象。
     1.(InputStream/OutputStream)    为字节输入/输出流,这种读写方式都是按一定字节量读取数据。
     2. (FileInputStream/FileOutputStream) 此方法继承自上面的(InputStream/OutpustStream),同样按字节流输入/输出,用于读取图像之类的原始字节流
     3.(FileReader/FileWriter) 此方法适用于按字符流的文件操作
     4. (BufferedReader/BufferedWriter) 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
 
      注:更详细的IO操作说明,请查看具体的JDK文档。
  此处我采用的BufferedReader按行读取,代码片段:
 1     public static List<String> getLogLinesByBuf(String filePath){
 2         
 3         List<String> items = new ArrayList<String>();
 4         File file = new File(filePath);    
 5         BufferedReader reader;
 6         if (file.exists()) {
 7             
 8             try {
 9                 reader = new BufferedReader(new FileReader(file));
10                 String temp = "";
11                 while((temp = reader.readLine()) != null) {
12                     items.add(temp);
13                 }            
14                 //close
15                 reader.close();
16             } catch (Exception e) {                
17                 e.printStackTrace();
18             }
19         } else {
20             System.out.println("该路径文件不存在.");
21         }        
22         return items;
23     }

 

PreparedStatement和Statement 
        JDBC操作我们经常会用到PreparedStatement和Statement,PreparedStatement相对Statement来讲,PreparedStatement拥有预编译能力,性能更好,2者其它的优缺点比较可以查看相关的资料。另外,平常我们插入数据都是一条,2条,当完成成千上万条数据插入操作的时候,你会看到性能是直线下降的,所以这里会采用sql批处理。
       代码片段:
    
    public static void insertLogInfo(List<String> data) {
        
        String sql = "INSERT INTO log_info(date_time,s_sitename,s_ip,cs_method,cs_uri_stem,cs_uri_query,"
                + "s_port,cs_username,c_ip,cs_user_agent,sc_status,sc_substatus,sc_win32_status"
                + ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)";
        Connection conn = DBSource.getConnection();
        int count = 0;
        try {
            conn.setAutoCommit(false);
            PreparedStatement prest = conn.prepareStatement(sql);  
            
            for(String str : data) {
                String[] arr = str.split(" ");
                prest.setString(1, arr[0]+" "+arr[1]);
                prest.setString(2, arr[2]);
                prest.setString(3, arr[3]);
                prest.setString(4, arr[4]);
                prest.setString(5, arr[5]);
                prest.setString(6, arr[6]);
                prest.setString(7, arr[7]);
                prest.setString(8, arr[8]);
                prest.setString(9, arr[9]);
                prest.setString(10, arr[10]);
                prest.setString(11, arr[11]);
                prest.setString(12, arr[12]);
                prest.setString(13, arr[13]);
                //添加到批处理
                prest.addBatch();    
            }

            int [] intarr = prest.executeBatch();
            conn.commit();  
            prest.clearBatch();                      
            prest.close();
            conn.close();
            for (int j = 0 ; j < intarr.length; j++) {
                if (intarr[j] > 0) {
                    count +=1;
                }
            }    
        } catch (Exception e) {
            System.out.println(new Date().toLocaleString()+":数据库插入操作失败"+e.getMessage());
        }      
        System.out.println("本次操作成功插入"+count+"行数据");    
    }
View Code

 

相关文章:

  • 2021-09-29
  • 2021-08-12
  • 2021-08-22
  • 2021-04-01
  • 2021-06-23
猜你喜欢
  • 2022-02-27
  • 2021-08-04
  • 2022-01-06
  • 2021-09-26
相关资源
相似解决方案