【问题标题】:java sqlite autocommit slowjava sqlite自动提交慢
【发布时间】:2014-10-06 18:51:12
【问题描述】:

背景:我正在 Netbeans 中使用 Java。

我正在从 CSV 文件中读取行并将它们插入到 SQLite 数据库中。我认为非常基本的东西。根据在本网站和其他地方找到的示例,我构建了以下代码。它有效,但我很惊讶它有多慢。将 46 行加载到 db 需要 3.95 秒!使用 Netbeans Profiler,我可以看到 autoCommit() 占用了大部分时间,3.7 秒。

我做错了什么?或者,这只是使用 SQLite 而不是 MySQL 的惩罚吗?

      public static void LoadJCNAClassesTable(Connection aConn, String strPath) throws SQLException{
    String [] nextLine;
    String strDivision;
    String strClass;
    String strNotes;
    String strDescription;

    Statement stat = aConn.createStatement(); 
    stat.executeUpdate("drop table if exists JCNAClasses;"); 
    String q = "create table JCNAClasses ('ID'  INTEGER PRIMARY KEY AUTOINCREMENT, 'division' TEXT NOT NULL, 'class' TEXT NOT NULL UNIQUE, 'description' TEXT NOT NULL, 'note'  TEXT NOT NULL, 'node' INTEGER NOT NULL);";
    stat.executeUpdate(q);
    CSVReader reader;
    int iLine;

    String JCNAClassesCSV = strPath + "\\JCNAClassesCsv.txt" ;

    try {
        reader = new CSVReader(new FileReader(JCNAClassesCSV ));
        iLine = 0;
        while ((nextLine = reader.readNext()) != null) {
            // nextLine[] is an array of values from the line
        // System.out.println(nextLine[0] + nextLine[1] );
            if (iLine > 0){
                strDivision = nextLine[0];
                strClass = nextLine[1];
                strDescription= nextLine[2];
                strNotes= nextLine[3];
                PreparedStatement prep = aConn.prepareStatement( "insert into JCNAClasses ('division', 'class', 'description', 'note', 'node') values ( ?,  ?,  ?,  ?,  ?);"); 
                prep.setString(1, strDivision); // note that the comma seems not to be a problem
                prep.setString(2,strClass); 
                prep.setString(3,strDescription); 
                prep.setString(4,strNotes); 
                prep.setInt(5,iLine); 
                prep.addBatch(); 
                aConn.setAutoCommit(false); 
                prep.executeBatch(); 
                aConn.setAutoCommit(true); 

            }
            iLine++;
        }
    }    catch (FileNotFoundException ex) {
            Logger.getLogger(Entries.class.getName()).log(Level.SEVERE, null, ex);
        }    
        catch (IOException ex) {
            Logger.getLogger(Entries.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException ex) {
            Logger.getLogger(LoadSQLiteConcoursDatabase.class.getName()).log(Level.SEVERE, null, ex);
        }
  }

    public static void LoadConcoursEntriesTable(Connection aConn,  String strPath) throws SQLException{ 
String [] nextLine;
String strEntryName;
String strClass;
Integer intYear;
String strDescription;
String strOwnerFirst;
String strOwnerLast;
Integer intJCNA;
String strColor;
String strPlate;
Integer intNode;
Long intPersonnel_id;
Long  intJaguar_id;
ResultSet generatedKeys;
String strStatus;
int intPersonnelNode;
ResultSet r;

CSVReader reader;
String q;
int iLine;
PreparedStatement prep;
ResultSet rs;
Statement stat = aConn.createStatement();
//
// Concourse Personnel Table:  Owners, Judges, & Interested parties
//
stat.executeUpdate("drop table if exists ConcoursPersonnel"); 
// status:  Owner = "O";  "J"  = Judge;  "OJ" = Owner & Judge;  "IP" = Interested party, e.g., spouse, restorer
q = "create table ConcoursPersonnel ('personnel_id' INTEGER PRIMARY KEY AUTOINCREMENT ,  'ownerfirst' TEXT NOT NULL, 'ownerlast' TEXT NOT NULL, 'jcna' INTEGER NOT NULL UNIQUE ON CONFLICT IGNORE, 'status' TEXT NOT NULL, 'node' INTEGER NOT NULL UNIQUE)";
stat.executeUpdate(q);

//
// Concours Jaguar  Table
//
stat.executeUpdate("drop table if exists ConcoursJaguars"); 
q  = "create table ConcoursJaguars ('jaguar_id' INTEGER PRIMARY KEY AUTOINCREMENT , 'class' TEXT NOT NULL, 'year' TEXT NOT NULL, 'description' TEXT NOT NULL, 'Color' TEXT, 'plate' TEXT, 'node' INTEGER NOT NULL UNIQUE)";
stat.executeUpdate(q);

//
// Entry  Table ( a Relationship or "link" between Personnel & Jaguars
//
stat.executeUpdate("drop table if exists ConcoursEntries"); 
q  = "create table ConcoursEntries (entry_name TEXT NOT NULL, personnel_id INTEGER NOT NULL, jaguar_id INTEGER NOT NULL, UNIQUE (personnel_id, jaguar_id), FOREIGN KEY (personnel_id) REFERENCES ConcoursPersonnel (Personnel_ID), FOREIGN KEY (jaguar_id) REFERENCES ConcoursPersonnel (jaguar_id))";
stat.executeUpdate(q);
String EntriesCSV = strPath + "\\EntriesCsv.txt" ;
strStatus = "O"; // not in the CSV data so set to Owner
try {
    reader = new CSVReader(new FileReader(EntriesCSV ));
    iLine = 0;
    while ((nextLine = reader.readNext()) != null) {
        // nextLine[] is an array of values from the line
        // System.out.println(nextLine[0] + nextLine[1] );
        if (iLine > 0){
            strEntryName = nextLine[0];
            strClass = nextLine[1];
            intYear= Integer.parseInt(nextLine[2]);
            strDescription= nextLine[3];
            strOwnerFirst= nextLine[4];
            strOwnerLast= nextLine[5];
            intJCNA = Integer.parseInt(nextLine[6]) ;
            strColor= nextLine[7];
            strPlate= nextLine[8];
            intNode= Integer.parseInt(nextLine[9]); // Since Jaguars are 1-to-1 with Entries this is used as Node number for both. However, it can't be used for Personnel Node 
            // 
            // Load Owners into Personnel Table
            //
            Statement s = aConn.createStatement();
            r = s.executeQuery("SELECT COUNT(*) AS rowcount FROM ConcoursPersonnel");
            r.next();
            intPersonnelNode = r.getInt("rowcount") +1 ; // Assignes Personnel node numbers as a continuous sequence

            prep = aConn.prepareStatement( "insert into ConcoursPersonnel ('ownerfirst', 'ownerlast', 'jcna', 'status', 'node' ) values ( ?,  ?,  ?,  ?,  ?);"); 
            //prep.setString(1, strEntryName); // note that the comma seems not to be a problem
            prep.setString(1,strOwnerFirst); 
            prep.setString(2,strOwnerLast); 
            prep.setInt(3,intJCNA); 
            prep.setString(4,strStatus); 
            prep.setInt(5,intPersonnelNode); 
            prep.addBatch(); 
            aConn.setAutoCommit(false); // starts transaction
            prep.executeBatch(); 
            aConn.setAutoCommit(true);  // ends transaction 

            aConn.setAutoCommit(false); // starts transaction
            stat = aConn.createStatement();
            generatedKeys = stat.executeQuery("SELECT last_insert_rowid()");
            intPersonnel_id = 0L; // won't be used
            if (generatedKeys.next()) {
                intPersonnel_id = generatedKeys.getLong(1);
            }
            else{
                System.out.println("No Personnel ID found in LoadConcoursEntriesTable");
                System.exit(-1);
            }
            aConn.setAutoCommit(true); // Commits transaction.
            //
            // Load Entry cars into the ConcoursJaguars table
            //
            prep = aConn.prepareStatement( "insert into ConcoursJaguars ('class', 'year', 'description', 'color', 'plate', 'node' ) values ( ?,  ?,  ?,  ?,  ?, ?);"); 
            prep.setString(1,strClass); 
            prep.setInt(2,intYear);
            prep.setString(3,strDescription); 
            prep.setString(4,strColor); 
            prep.setString(5,strPlate);
            prep.setInt(6,intNode);  //                                        
            prep.addBatch(); 
            aConn.setAutoCommit(false); 
            prep.executeBatch(); 
            aConn.setAutoCommit(true); 

            q =  "select jaguar_id from ConcoursJaguars where node == " + intNode + ";";
            rs = stat.executeQuery(q);
            intJaguar_id = rs.getLong("jaguar_id");

            prep = aConn.prepareStatement( "insert into ConcoursEntries (entry_name, personnel_id, jaguar_id) values ( ?,  ?, ?);"); 
            //prep.setString(1, strEntryName); // note that the comma seems not to be a problem
            prep.setString(1,strEntryName); 
            prep.setLong(2,intPersonnel_id); 
            prep.setLong(3,intJaguar_id);
            prep.addBatch(); 
            aConn.setAutoCommit(false); 
            prep.executeBatch(); 
            aConn.setAutoCommit(true); 
        }
        iLine++;
    }
}    catch (FileNotFoundException ex) {
        Logger.getLogger(Entries.class.getName()).log(Level.SEVERE, null, ex);
    }    
    catch (IOException ex) {
        Logger.getLogger(Entries.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SQLException ex) {
        Logger.getLogger(LoadSQLiteConcoursDatabase.class.getName()).log(Level.SEVERE, null, ex);
    }

}

【问题讨论】:

    标签: java sqlite autocommit


    【解决方案1】:

    将 autoCommit 设置为 true 实际上是在循环内执行提交。因此,没有批处理操作在运行:每次迭代循环时都提交。要进行批处理操作,您需要:

    1. while 运算符之前添加aConn.setAutoCommit(false);
    2. 删除包裹prep.executeBatch(); 的行(即aConn.setAutoCommit(false);aConn.setAutoCommit(true);
    3. prep.executeBatch(); 移出循环
    4. 在您的 while 循环之后添加 aConn.commit();
    aConn.setAutoCommit(false); PreparedStatement prep = aConn.prepareStatement( "insert into JCNAClasses ('division', 'class', 'description', 'note', 'node') values ( ?, ?, ?, ?, ?);"); while ((nextLine = reader.readNext()) != null) { if (iLine > 0){ // some preparations go here prep.addBatch(); } iLine++; } prep.executeBatch(); aConn.commit();

    【讨论】:

      【解决方案2】:

      每次执行循环时,您都在重新创建 PreparedStatement。这应该移到 while 循环之前。

      setAutoCommit 选项也应该在循环外设置一次,然后在达到合理上限或完成时提交语句。

      您可以在此处查看发布的示例:Java: Insert multiple rows into MySQL with PreparedStatement

      【讨论】:

      • 这解决了构建我给的单个表的问题,但是我有其他表有关系。特别是,我有一个我称之为“条目”的 CSV 文件(如在车展中),其中每个条目都有一个所有者和一辆或多辆汽车。我希望将 Cars 放在一个表中,将 Owners 放在另一个表中,并带有一个名为 Entries 的链接表。我在一个循环中构建这 3 个表,扫描 Entries.csv 文件。在这种情况下,我不能跳过 Owner 和 Car 表中的 executeBatch(),因为如果它们没有完成,我将没有用于插入 Entries 表的外键。
      • 您能否将 3 个表格及其关系以及 CSV 文件的格式添加到您的问题中?
      • 我添加了 LoadConcoursEntriesTable() 的代码,它创建了 Personnel 表、Juguars 表,然后是 Entries 链接表。 CVS 文件的格式在代码中很明显,但如果您愿意,我可以提供文件本身。它有 41 行。
      • 仍然没有解决第二个问题的方法,即按照预期快速构建链接表。我可以接受我正在做的事情,因为一旦我将整个应用程序放入 Java 中,我就不必从 CSV 加载我的表。如果有人知道如何做得更好,我肯定想听听。因为我不经常访问这个论坛,所以给我发电子邮件至 jag_mab653@sbcglobal.net。 TIA
      猜你喜欢
      • 1970-01-01
      • 2011-03-04
      • 1970-01-01
      • 2021-06-01
      • 2016-07-19
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多