溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java jdbc批量多線程讀取CVS文件入庫(kù)

發(fā)布時(shí)間:2020-09-19 20:55:10 來(lái)源:腳本之家 閱讀:192 作者:吳林 欄目:編程語(yǔ)言

需求是這樣的:現(xiàn)在需要測(cè)試一個(gè)內(nèi)存數(shù)據(jù)庫(kù)的入庫(kù)性能,要求測(cè)試每線程準(zhǔn)備一個(gè)文件,10個(gè)線程入庫(kù)總計(jì)100w記錄數(shù)的單表入庫(kù)性能。

知識(shí)點(diǎn):jdbc + 多線程 + 批處理 + 文件讀取

先來(lái)看看我的代碼結(jié)構(gòu)

Java jdbc批量多線程讀取CVS文件入庫(kù)

說(shuō)明:

files: 存放即將要讀取的文件。
lib: 存放第三方的jar文件,例如數(shù)據(jù)庫(kù)驅(qū)動(dòng)包。
MemSqlTestMain: 這是工程的入口,就是主程序。
DBUtil: 這個(gè)類(lèi)是數(shù)據(jù)庫(kù)幫助類(lèi),主要讀取數(shù)據(jù)庫(kù)配置信息獲取連接關(guān)閉連接等操作。
InsertUtil: 主要做的是讀取數(shù)據(jù)文件生成sql并批量入庫(kù)的一個(gè)類(lèi)。
TableDataInfo: 主要對(duì)要插入的數(shù)據(jù)表的對(duì)象的一個(gè)類(lèi)。
XMLUtil: 讀取XML配置文件
config.xml: 配置要插入的表信息以及文件的路徑等信息
dbconfig.properties: 主要對(duì)數(shù)據(jù)庫(kù)的連接信息進(jìn)行存儲(chǔ),包括URL,用戶名密碼等等。

話不多說(shuō)直接上代碼:

import java.util.ArrayList;
/**
 * @param
 * @author wu.lin
 * @description 程序入口,啟用線程讀取文件并入庫(kù)
 * @create 2016年09月01日 15:12
 * @throws
 */
public class MemSqlTestMain {

 public static void main(String[] args) {

  //通過(guò)讀取配置文件讀取要插入數(shù)據(jù)的表名
  String tableName = XMLUtil.getTableName();
  System.out.println(tableName);

  //通過(guò)配置文件讀取數(shù)據(jù)存放的文件的路徑
  ArrayList<String> fileNameList = XMLUtil.getFileNameList();
  int len = fileNameList.size();

  //針對(duì)每一個(gè)文件開(kāi)啟一個(gè)進(jìn)程去執(zhí)行讀取并入庫(kù)的操作
  for (int i = 0; i < len; i++) {

   String fileName = fileNameList.get(i);
   System.out.println(fileName);

   new Thread(new InsertUtil(fileName, tableName)).start();
  }

 }
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.*;

/**
 * @param
 * @author wu.lin
 * @description InsertUtil是一個(gè)線程類(lèi),主要讀取數(shù)據(jù)文件組裝Sql并執(zhí)行入庫(kù)操作
 * @create 2016年09月01日 14:10
 * @throws 
 */
public class InsertUtil implements Runnable {

 //文件路徑
 private String filePath;

 //表名
 private String tableName;

 //.cvs文件數(shù)據(jù)以","分隔
 private static String DELIMITERS = ",";

 //獲取數(shù)據(jù)庫(kù)幫助類(lèi)
 DBUtil dbutil = DBUtil.getInstance();

 public InsertUtil() {}

 public InsertUtil(String filePath, String tableName) {
  this.filePath = filePath;
  this.tableName = tableName;
 }

 public static String getDELIMITERS() {
  return DELIMITERS;
 }

 public static void setDELIMITERS(String delimiters) {
  DELIMITERS = delimiters;
 }

 public String getFilePath() {
  return filePath;
 }

 public void setFilePath(String filePath) {
  this.filePath = filePath;
 }


 //讀取文件并且批處理入庫(kù)的方法
 public boolean insertDB(String tablename, long rc, String filePath) {

  if(filePath == null || "".equals(filePath)) {
   System.out.println("文件路徑為空");
   return false;
  }
  if (rc < 1) {
   rc = 100;
  }

  Connection conn = null;
  boolean flag = false;
  Statement pre = null;

  String sql = "";

  TableDataInfo tableInfo = new TableDataInfo();

  try {

   if(conn == null) {
    conn = dbutil.getConnection();
   }

   pre = conn.createStatement();

   conn.setAutoCommit(false);

   int colCount = tableInfo.getTableColNums(tablename, conn);

   int rowCount = 0;

   File file = new File(filePath);

   BufferedReader buf = null;
   buf = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

   String line_record = buf.readLine();

   long startTime = System.currentTimeMillis(); //開(kāi)始計(jì)時(shí)

   while (line_record != null) {
    // 解析每一條記錄
    sql = "INSERT INTO " + tablename + " VALUES('";

    String[] fields = line_record.split(DELIMITERS);

    //對(duì)Insert語(yǔ)句的合法性進(jìn)行判斷

    if(fields.length != colCount){
     System.out.println("要插入的數(shù)據(jù)列數(shù)和表的數(shù)據(jù)列不相匹配,停止執(zhí)行");
     break;
    }


    for (int i = 0; i < fields.length; i++) {

     sql += fields[i];
     if (i < fields.length - 1) {
      sql += "','";
     }
    }

    sql += "');";

    // 在控制臺(tái)輸出SQL語(yǔ)句
    // System.out.println(sql);

    //執(zhí)行SQL語(yǔ)句
    pre.addBatch(sql);


    rowCount++;
    line_record = buf.readLine();

    if (rowCount >= rc) {
     break;
    }

   }
   pre.executeBatch();
   conn.setAutoCommit(true);

   pre.close();


   System.out.println("共寫(xiě)入行數(shù):" + rowCount);

   long endTime = System.currentTimeMillis(); //停止計(jì)時(shí)

   System.out.println("執(zhí)行時(shí)間為:" + (endTime - startTime) + " ms");

  } catch (Exception e) {

   flag = false;
   try {
    //回滾
    if(conn != null) {
     conn.rollback();
    }
   } catch (SQLException e1) {
    e1.printStackTrace();
   }
   e.printStackTrace();
  } finally {
   dbutil.close(null, pre, conn);
  }
  return flag;
 }

 public void run() {
  this.insertDB(tableName, 500000, filePath);
 }

}
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @param
 * @author wu.lin
 * @description 數(shù)據(jù)庫(kù)表實(shí)體
 * @create 2016年09月01日 14:19
 * @throws
 */
public class TableDataInfo {

 DBUtil dbutil = DBUtil.getInstance();

 /**
  *
  * @param m_TableName
  * @param m_Connection
  * @return 該表的列數(shù)
  */
 public int getTableColNums(String m_TableName, Connection m_Connection) {

  int colCount = 0;

  try {
   if (m_Connection == null) {

    m_Connection = dbutil.getConnection();
   }

   DatabaseMetaData m_DBMetaData = m_Connection.getMetaData();

   ResultSet tableRet = m_DBMetaData.getTables(null, "%", m_TableName,
     new String[] { "TABLE" });

   while (tableRet.next()) {
    System.out.println("Table name is:"
      + tableRet.getString("TABLE_NAME"));
   }

   String columnName;
   String columnType;
   ResultSet colRet = m_DBMetaData.getColumns(null, "%", m_TableName,"%");

   while (colRet.next()) {

    columnName = colRet.getString("COLUMN_NAME");
    columnType = colRet.getString("TYPE_NAME");
    int dataSize = colRet.getInt("COLUMN_SIZE");
    int digits = colRet.getInt("DECIMAL_DIGITS");
    int nullable = colRet.getInt("NULLABLE");

    String nullFlag;

    if (nullable == 1) {
     nullFlag = "Null";
    } else {
     nullFlag = "Not Null";
    }

    System.out.println(columnName + " " + columnType + "("
      + dataSize + "," + digits + ") " + nullFlag);
    colCount++;
   }

  } catch (SQLException e) {
   e.printStackTrace();
  }

  System.out.println("The number of column is: " + colCount);
  return colCount;
 }
}

接下來(lái)就剩下讀取配置文件的代碼了,先來(lái)看看配置文件內(nèi)容(這里配置了數(shù)據(jù)庫(kù)配置文件路徑表名以及文件存放的相對(duì)路徑):

<?xml version="1.0" encoding="utf-8" ?>
<config>
 <db_file>src/dbconfig.properties</db_file>
 <tableName>memtest</tableName>
 <files>
  <filePath>files/memtest.csv</filePath>
  <filePath>files/memtest_1.csv</filePath>
  <filePath>files/memtest_2.csv</filePath>
  <filePath>files/memtest_3.csv</filePath>
  <filePath>files/memtest_4.csv</filePath>
  <filePath>files/memtest_5.csv</filePath>
  <filePath>files/memtest_6.csv</filePath>
  <filePath>files/memtest_7.csv</filePath>
  <filePath>files/memtest_8.csv</filePath>
  <filePath>files/memtest_9.csv</filePath>
  <filePath>files/memtest_10.csv</filePath>
 </files>
</config>

接下來(lái)是讀取這個(gè)配置文件的內(nèi)容,比較簡(jiǎn)單,所以只貼部分代碼:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
import java.util.ArrayList;

/**
 * @param
 * @author wu.lin
 * @description 讀取配置信息
 * @create 2016年09月01日 15:45
 * @throws
 */
public class XMLUtil {

 //該方法用于從XML配置文件中提取要插入的表名稱,并返回該表名稱
 public static String getTableName() {

  return getXmlProperties("tableName");
 }

 public static String getDatabaseUrl() {
  return getXmlProperties("dataBaseUrl");
 }

 public static String getDbFilePath() {
  return getXmlProperties("db_file");
 }

 private static String getXmlProperties(String proName) {
  try {

   Document doc = getDoc();

   //獲取包含品牌名稱的文本節(jié)點(diǎn)
   NodeList nl = doc.getElementsByTagName(proName);
   Node classNode=nl.item(0).getFirstChild();
   String tableName=classNode.getNodeValue().trim();

   return tableName;
  } catch(Exception e)
  {
   e.printStackTrace();
   return null;
  }
 }

 private static Document getDoc() throws Exception {
  //創(chuàng)建文檔對(duì)象
  DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
  DocumentBuilder builder = dFactory.newDocumentBuilder();
  Document doc;
  doc = builder.parse(new File("src/config.xml"));

  return doc;
 }
}

數(shù)據(jù)庫(kù)配置信息文檔:

db.used=mysql

# driver class
oracle.jdbc.driver_class=oracle.jdbc.driver.OracleDriver
# URL
oracle.jdbc.url=jdbc:oracle:thin:@localhost:1521:ORCL
# username
oracle.jdbc.username=scott
# pwd
oracle.jdbc.pwd=tiger


#mysql connect config
mysql.jdbc.driver_class=com.mysql.jdbc.Driver
mysql.jdbc.url=jdbc:mysql://localhost:3306/mysqldb
mysql.jdbc.username=root
mysql.jdbc.pwd=

最后是數(shù)據(jù)庫(kù)幫助類(lèi),比較常見(jiàn):

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @param
 * @author wu.lin
 * @description 數(shù)據(jù)庫(kù)幫助類(lèi)
 * @create 2016年09月01日 18:56
 * @throws
 */

public class DBUtil {

 private static Properties env = new Properties();

 private static DBUtil dbutil;

 private static String dbname;

 private static String driverClass_key;

 private static String url_key;

 private static String username_key;

 private static String pwd_key;


 private DBUtil(){}

 // 單例模式
 public static synchronized DBUtil getInstance() {
  if (null == dbutil) {
   dbutil = new DBUtil();
  }
  return dbutil;
 }

 /**
  * 得到數(shù)據(jù)庫(kù)連接
  * @return
  */
 public Connection getConnection() {
  Connection conn = null;

  try {
   env.load(new FileInputStream(XMLUtil.getDbFilePath()));

   dbname = env.getProperty("db.used").toLowerCase();

   driverClass_key = dbname + ".jdbc.driver_class";
   url_key = dbname + ".jdbc.url";
   username_key = dbname + ".jdbc.username";
   pwd_key = dbname + ".jdbc.pwd";

   //加載連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序類(lèi)文件
   Class.forName(env.getProperty(driverClass_key));
   conn = createConnection();

  } catch (Exception e) {

   e.printStackTrace();
  }

  return conn;
 }

 private Connection createConnection() throws SQLException {

  Connection conn = null;
  if ("oracle".equals(dbname)) {

   conn = DriverManager.getConnection(env.getProperty(url_key), env.getProperty(username_key),
     env.getProperty(pwd_key));
  }

  if ("sqlserver".equals(dbname)) {

   conn = DriverManager.getConnection(env.getProperty(url_key), env.getProperty(username_key),
     env.getProperty(pwd_key));

  }

  if ("mysql".equals(dbname)) {
   // 其他數(shù)據(jù)庫(kù)的連接語(yǔ)法
   String url = env.getProperty(url_key);
   String username = env.getProperty(username_key);
   String pwd = env.getProperty(pwd_key);

   if(username != null && !"".equals(username)) {
    url += ("?user=" + username);
    if(pwd != null && !"".equals(pwd)) {
     url += ("&password=" + pwd);
    }
   }

   conn = DriverManager.getConnection(url);
  }

  return conn;

 }

 //提供jdbc關(guān)閉連接的方法
 public void close(ResultSet rs,Statement st,Connection conn){

  try {
   if(rs!=null)
    rs.close();
   if(st!=null)
    st.close();
   if(conn!=null)
    conn.close();
  } catch (SQLException e) {

   e.printStackTrace();
  }
 }
}

最后的工作便是在文件目錄存放相應(yīng)的數(shù)據(jù)文件,然后通過(guò)配置文件配置好文件名、表名以及數(shù)據(jù)庫(kù)連接的基本信息后,運(yùn)行程序入口,便可以將程序跑起來(lái)啦。但是在這個(gè)過(guò)程中也遇到一些小問(wèn)題,比如,我這邊只有一個(gè)100w條數(shù)據(jù)的.csv格式的文件,但是要求讀取十個(gè)文件,在這個(gè)時(shí)候我用到了一個(gè)小工具:

Java jdbc批量多線程讀取CVS文件入庫(kù)

大家知道.csv格式的文件也可以用Excel軟件打開(kāi),所以在這里轉(zhuǎn)換一下用Excel分割器把文件分成十份,就完美的解決問(wèn)題啦。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI