当前位置: 首页 > 知识库问答 >
问题:

如何在从JSONArray向SqLite插入/更新10000行时防止应用程序崩溃

扈昀
2023-03-14

我正在尝试将所有数据从Mysql数据库重新加载到SqLite数据库。我有10000行,试图用一个命令更新Sqlite。

我可以使用这些函数更新任何我的sqlite数据,但是当它有很多行时,应用程序崩溃

Android数据库游标窗口分配异常:2048 kb的游标窗口分配失败打开游标=608(#此进程打开的游标=608)

在阅读一些文章之前,我对ContentValues做了这项工作,我发现使用SQLiteStatement可以大大提高插入/更新速度。

我是这样做的:

KeyTypePair包括以下列名称和类型,12列:

public static final String[][] KEYS_TYPES = {
        new String[] { "id_field", "int"},
        new String[] { "text", "string" }
        ................. and so on..................
}

DBDatabase.java

private SQLiteDatabase db;

这从mysql获取10000行,并尝试插入/更新到sqlite

public void addAll(JSONArray ARRAY, String TABLE, String IDFIELD, String[][] KEYS_TYPES) {
    long startTime = System.currentTimeMillis();
    SQLiteDatabase db = this.getWritableDatabase();

    String sqlPrepared = sqlPrepared(KEYS_TYPES);

    if(doesTableExist(db, TABLE)) {
        try {
            for (int i = 0; i < ARRAY.length(); i++) {
                JSONObject ROW = ARRAY.getJSONObject(i);

                int id = getId(ROW, IDFIELD);

                String where = " WHERE " + IDFIELD + "=" + id;

                add(ROW, TABLE, IDFIELD, id, sqlPrepared, where, KEYS_TYPES);
            }
            long difference = System.currentTimeMillis() - startTime;
            Log.e("add all timing", new Long(difference).toString());
        } catch (JSONException e) {
            voids.debugMsg(context, "SQLite addAll ERROR: " + e.toString());
        }
    } else {
        voids.debugMsg(context, "TABLE " + TABLE + " NOT EXIST, LETS TRY AGAIN..");
        createTable(db, TABLE);
        addAll(ARRAY, TABLE, IDFIELD, KEYS_TYPES);
    }
}

这将完成实际的插入

public void add(JSONObject object, String TABLE, String ID, int id, String sqlPrepared, String where, String[][] keyTypePair) {
    db.beginTransaction();
    String sql = "";
    if(dataExist(TABLE, ID, id)) {
        sql = "UPDATE " + TABLE + " SET " + sqlPrepared + where;
    } else {
        sql = "INSERT INTO " + TABLE + " SET " + sqlPrepared;
    }

    try {
        SQLiteStatement stmt = db.compileStatement(sql);
        stmt = bindValues(keyTypePair, stmt, object);
        stmt.execute();
    } finally {

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

这将创建用于更新和插入的部分准备字符串

public String sqlPrepared(String[][] keyTypePair) {
    String columnString = "";
    for (int i = 0; i < keyTypePair.length; i++) {
        String[] pair = keyTypePair[i];
        String KEY = pair[0];
        if(keyTypePair.length!=i+1) {
            columnString += KEY + "=?, ";
        } else {
            columnString += KEY + "=?";
        }

    }
    columnString += "";
    return columnString;
}

这只是为了从JSONObject获取id

private int getId(JSONObject OBJECT, String ID) {
    int id = 0;
    try {
        id = OBJECT.getInt(ID);
    } catch (JSONException e) {
        Log.e("DBDatabase ERROR: ", "ERROR WHILE TRYING TO ADD TO SQLite: "+e.toString());
    }
    return id;
}

这将检查SqLite数据库中是否存在行

public boolean dataExist(String TABLE, String IDFIELD, int ID) {
    boolean exist = false;
    String[] columns = {IDFIELD};
    Cursor cursor =
            db.query(TABLE,
                    columns, // b. column names
                    IDFIELD + " = ?", // c. selections
                    new String[]{String.valueOf(ID)}, // d. selections args
                    null, // e. group by
                    null, // f. having
                    null, // g. order by
                    null); // h. limit
    if (cursor.getCount()>0) {
        exist = true;
    }
    return exist;
}

以下是当应用程序崩溃时我对logcat的看法:

08-24 17:02:06.137    9522-9522/.DBService E/Zygote﹕ MountEmulatedStorage()
08-24 17:02:06.137    9522-9522/.DBService E/Zygote﹕ v2
08-24 17:02:06.167    9522-9522/.DBService E/SELinux﹕ [DEBUG] get_category: variable seinfo: default sensitivity: NULL, cateogry: NULL
08-24 17:02:13.687    9522-9522/.DBService E/CursorWindow﹕ Could not allocate CursorWindow '/data/data/my.app/databases/myDB' of size 2097152 due to error -12.
08-24 17:02:13.697    9522-9522/.DBService E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: .DBService, PID: 9522
android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=608 (# cursors opened by this proc=608)
        at android.database.CursorWindow.<init>(CursorWindow.java:108)
        at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
        at android.database.sqlite.SQLiteCursor.clearOrCreateWindow(SQLiteCursor.java:301)
        at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:139)
        at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
        at my.app.MyDatabase.dataExist(MyDatabase.java:569)
        at my.app.MyDatabase.add(MyDatabase.java:392)
        at my.app.MyDatabase.addAll(MyDatabase.java:407)
        at my.app.MyReceiver$1.onSuccess(MyReceiver.java:37)
        at my.app.SocketManager$1.onPostExecute(SocketManager.java:121)
        at my.app.SocketManager$1.onPostExecute(SocketManager.java:58)
        at android.os.AsyncTask.finish(AsyncTask.java:632)
        at android.os.AsyncTask.access$600(AsyncTask.java:177)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:5832)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

共有1个答案

林弘文
2023-03-14

在你的dataExist()中,你需要在返回之前关闭光标。

public boolean dataExist(String TABLE, String IDFIELD, int ID) {
    boolean exist = false;
    String[] columns = {IDFIELD};
    Cursor cursor =
            db.query(TABLE,
                    columns, // b. column names
                    IDFIELD + " = ?", // c. selections
                    new String[]{String.valueOf(ID)}, // d. selections args
                    null, // e. group by
                    null, // f. having
                    null, // g. order by
                    null); // h. limit
    if (cursor.getCount()>0) {
        exist = true;
    }
    cursor.close();
    return exist;
}
 类似资料:
  • 即使在谷歌搜索了几个小时后,我也无法找出确切的问题。我已经检查了StackOverflow本身的几个答案,但未能找出问题所在。 错误跟踪如下: 主要活动代码: 更新1:我已经做了答案中建议的所有更改,但每当我单击MainActivity中的“跳过指令”按钮时,我的应用程序仍然崩溃。此外,当我从AdminLogin活动中单击“登录”按钮时,应用程序崩溃。我该怎么办? Update2:我提到了什么是N

  • 问题内容: 以下是开始对话的几种可能性: 初始化后转义所有输入。 转义每个值,最好在生成SQL时转义。 第一种解决方案是次优的,因为如果要在除SQL之外的其他任何方式中使用每个值,则需要取消转义每个值,例如在网页上输出它。 第二种解决方案更有意义,但是手动转义每个值是一件痛苦的事情。 我知道已准备好的语句,但是我发现MySQLi麻烦。另外,将查询与输入分离也使我感到担忧,因为尽管正确执行订单至关重

  • 我让我的学长给我解释,他说, 这是为了防止生产中的崩溃。 我完全不同意。对我来说,这不是防止应用程序崩溃的方法。这表明开发人员不知道他/她在做什么,并有疑问。 由于这个问题得到了很多关注,有些人误解了这个问题(可能是因为我没有清楚地表达它),我打算重新表达它。 以下是开发人员在这里所做的 > 编写并测试一个函数,它可以是一个只是初始化视图的小函数,也可以是一个复杂的函数,测试后它被包裹在块中。即使

  • 当我在1到9之间选择一个数字并在控制台中输入一个数字时,该方法会工作并进行正确的移动。但我的问题是如何避免当我输入一个字母而不是一个数字时,程序就崩溃了。

  • 问题内容: 我正在寻找一些防止SQL注入的技巧。在一个论坛上告诉我我的代码不安全,我正在寻找一个足够好的人来帮助我解决此问题。 我有一个Web表单,提交后转到aspx.cs页,然后将数据插入ms sql数据库。 问题答案: 最直接的解决方法是 不 通过将字符串串联在一起来构建sql,而是使用params。如果您使用的是SqlCommand,则可以执行以下操作,否则按照@MarcB的建议进行操作

  • 我正在登录页面上工作,基于Androidhive教程和问题是在2布局下工作正常,但对于3布局应用程序将崩溃。 在androidhive教程中使用了2布局,但我想使用3,因为我收到短信然后otp然后注册,所以问题是3rd布局,它不会出现并崩溃。 Androidhive教程链接:第1部分第2部分 以下是代码: XML Java Logcat 08-29 10:48:12.426 4499-4499/i

  • 我有以下三张桌子。请原谅表名,它们是通用数据库结构命名转换的一部分。 我想编写一个查询,使用匹配的值将值插入多对多表:tbl_331_to_tbl_320_字段。如果我使用DO NOTHING参数,这是有效的。 此语句用于插入找到匹配的值。 但是我想使用DO UPDATE,所以如果有冲突,它将更新第二个id(S.id)。例如,如果我将S.field_3中的值更改为与新ID匹配的其他值,我想更新这个

  • 问题内容: 我不想拥有用户或位置,因为我可以有多行用户包含相同数据,或者有多行位置包含相同数据。我只想避免用户和位置都具有一定的价值,因为该行重复了许多次。 例如:这还可以 但这不行: 因为已经存在其中user = 1和location = 2的行。 如何避免重复? 问题答案: 声明对(用户,位置)的唯一约束。