在Android设备上批量插入

时间:2010-10-04 23:55:12

标签: android sqlite bulkinsert

我希望在下次升级时将大约700条记录批量插入Android数据库。最有效的方法是什么?从各种帖子中,我知道如果我使用Insert语句,我应该将它们包装在一个事务中。关于使用您自己的数据库还有一个post,但我需要将这些数据放入我的应用程序的标准Android数据库中。请注意,每个设备只能执行一次。

一些想法:

  1. 将一堆SQL语句放在一个文件中,一次读取一行,然后执行SQL。

  2. 将数据放入CSV文件,JSON,YAML或XML等等。一次阅读一行,然后执行db.insert()

  3. 弄清楚如何进行导入并对整个文件进行一次导入。

  4. 创建一个包含所有记录的sqlite数据库,将其复制到Android设备上,并以某种方式合并这两个数据库。

  5. [编辑]将所有SQL语句放在res / values中的单个文件中作为一个大字符串。然后一次读取一行并执行SQL。

  6. 最好的方法是什么?还有其他加载数据的方法吗? 3和4甚至可能吗?

5 个答案:

答案 0 :(得分:97)

通常,每次使用db.insert()时,SQLite都会创建一个事务(以及文件系统中生成的日志文件),这会减慢速度。

如果你使用db.beginTransaction()db.endTransaction() SQLite只在文件系统上创建一个日志文件,然后同时提交所有插入,大大加快了速度。

以下是来自Batch insert to SQLite database on Android

的伪代码
try
{
  db.beginTransaction();

  for each record in the list
  {
    do_some_processing();

    if (line represent a valid entry)
    {
      db.insert(SOME_TABLE, null, SOME_VALUE);
    }

    some_other_processing();
  }

  db.setTransactionSuccessful();
}
catch (SQLException e) {}
finally
{
  db.endTransaction();
}

如果您希望因意外错误或某事而中止交易,只需db.endTransaction()而不先将交易设置为成功(db.setTransactionSuccessful())。

另一个有用的方法是使用db.inTransaction()(返回truefalse)来确定您当前是否处于交易过程中。

Documentation here

答案 1 :(得分:34)

我发现对于批量插入,(显然很少使用)DatabaseUtils.InsertHelper类比使用SQLiteDatabase.insert快几倍。

另外两项优化也有助于我的应用程序的性能,但它们可能并不适用于所有情况:

  • 请勿bind空值或null
  • 如果您可以某些可以安全地执行此操作,暂时关闭数据库的内部锁定也可以帮助提高性能。

我有一个blog post,其中包含更多详细信息。

答案 2 :(得分:9)

嗯,我对此的解决方案有点奇怪,但工作正常...... 我编译了大量数据并将其一次性插入(批量插入?)

我使用db.execSQL(Query)命令,并使用以下语句构建“查询”...

INSERT INTO yourtable SELECT * FROM (
    SELECT 'data1','data2'.... UNION
    SELECT 'data1','data2'.... UNION
    SELECT 'data1','data2'.... UNION
    .
    .
    .
    SELECT 'data1','data2'....
)

唯一的问题是查询的构建可能有点混乱。 我希望它有所帮助

答案 3 :(得分:9)

以下示例将完美地运作

 String sql = "INSERT INTO " + DatabaseHelper.TABLE_PRODUCT_LIST
                + " VALUES (?,?,?,?,?,?,?,?,?);";

        SQLiteDatabase db = this.getWritableDatabase();
        SQLiteStatement statement = db.compileStatement(sql);
        db.beginTransaction();
        for(int idx=0; idx < Produc_List.size(); idx++) {
            statement.clearBindings();
            statement.bindLong(1, Produc_List.get(idx).getProduct_id());
            statement.bindLong(2,  Produc_List.get(idx).getCategory_id());
            statement.bindString(3, Produc_List.get(idx).getName());
//            statement.bindString(4, Produc_List.get(idx).getBrand());
            statement.bindString(5, Produc_List.get(idx).getPrice());
            //statement.bindString(6, Produc_List.get(idx).getDiscPrice());
            statement.bindString(7, Produc_List.get(idx).getImage());
            statement.bindLong(8, Produc_List.get(idx).getLanguage_id());
            statement.bindLong(9, Produc_List.get(idx).getPl_rank());
            statement.execute();

        }
        db.setTransactionSuccessful();
        db.endTransaction();

答案 4 :(得分:8)

我不相信有任何可行的方法可以在你的名单上完成#3或#4。

在其他解决方案中,列出两个数据文件包含直接SQL,另一个包含非SQL格式的数据。

这三个都可以正常工作,但后者建议从格式化文件中获取数据并自己构建SQL似乎是最干净的。如果以后添加了真正的批量更新功能,则您的数据文件仍然可用,或者至少可以轻松地处理为可用的表单。此外,数据文件的创建更简单,更不容易出错。最后,拥有“原始”数据将允许导入其他数据存储格式。

在任何情况下,您应该(如您所述)将插入组包装到事务中,以避免创建每行事务日志。