【问题标题】:StackOverflowError when using a query in a recursive method在递归方法中使用查询时出现 StackOverflowError
【发布时间】:2018-06-17 20:42:53
【问题描述】:

在本地数据库中,我记录了有关目录和文件(文件系统树)的信息。例如,表“Dir”具有以下属性:record_id (autoincr.)、dir_iddirnameparentDir_id。 我需要从数据库创建一个文件和目录树:

Dir_1
|
 -----Dir_1.1
 -----Dir_1.2
 -----File_1.1
Dir_2
|
 -----Dir_2.1
 -----Dir_2.2
 -----File_2.1
 -----File_2.2
Dir_3
File_1
File_2

所以,我使用递归方法。 我的功能:

 /**
 * Append new childs for target dir
 * @param targetObject directory
 */
public void addChilds(@Nullable SimpleSyncDirModel targetObject){
    //no target - main parent dir.
    if (targetObject == null){
        //get childs for this target object (main dir without parent)
        ArrayList<Object> foundedChilds = ThisApp.getDBhelper().getSharedSimpleObjects(this.dir_id);
        //step by step (childs). recursive mecthod.
        for (Object thisChild : foundedChilds){
            if (thisChild instanceof SimpleSyncDirModel){
                addNewChildDir((SimpleSyncDirModel) thisChild);
                //find and add childs for current child
                addChilds((SimpleSyncDirModel) thisChild);
            }else if (thisChild instanceof SimpleSyncFileModel){
                addNewChildFile((SimpleSyncFileModel) thisChild);
            }
        }
    }else{
        //get childs for this target object (not main, has parent)
        ArrayList<Object> foundedChilds = ThisApp.getDBhelper().getSharedSimpleObjects(targetObject.dir_id);
        //iterate, find and append childs (recursive)
        for (Object thisChild : foundedChilds){
            if (thisChild instanceof SimpleSyncDirModel){
                targetObject.addNewChildDir((SimpleSyncDirModel) thisChild);
                //recursive
                addChilds((SimpleSyncDirModel) thisChild);
            }else if (thisChild instanceof SimpleSyncFileModel){
                targetObject.addNewChildFile((SimpleSyncFileModel) thisChild);
            }
        }

    }
}

如你所见,我使用函数

ThisApp.getDBhelper().getSharedSimpleObjects(targetObject.dir_id);

用于搜索目标目录的子目录。 targetObject.dir_id - "SELECT" 的 parent_id。

我的搜索子功能:

 /**
 * Get childs with parent_id == 0 (without parent) or not (with parent)
 * @param parendDir_id ID of dir, for what we search childs
 * @return list of childs like {@link SimpleSyncDirModel}
 * and {@link ru.rsit.megashare.models.global.SimpleSyncFileModel}
 */
public ArrayList<Object> getSharedSimpleObjects(String parendDir_id){

    ArrayList<Object> result = new ArrayList<>();

    //looking child dirs
    String[] columns_ = new String[]{
            "dir_id", "dirnameWithPath"
    };
    Cursor db_cursor = megashare_db.query(
            "SharedDir", columns_,
            "(parentDir_id = ?)",
            new String[] { parendDir_id },
            null, null, null);
    if (db_cursor.getCount() > 0) {
        db_cursor.moveToFirst();
        while (db_cursor.getPosition() != db_cursor.getCount()) {
            SimpleSyncDirModel simpleSyncDirModel = new SimpleSyncDirModel();
            simpleSyncDirModel.dir_id =
                    Integer.toString(db_cursor.getInt(db_cursor.getColumnIndex("dir_id")));
            simpleSyncDirModel.dirnameWithPath =
                    db_cursor.getString(db_cursor.getColumnIndex("dirnameWithPath"));
            result.add(simpleSyncDirModel);
            db_cursor.moveToNext();
        }
    }
    db_cursor.close();

    //looking child files
    columns_ = new String[]{
            "file_id", "filenameWithPath"
    };
    db_cursor = megashare_db.query(
            "SharedFile", columns_,
            "(parentDir_id = ?)",
            new String[] { parendDir_id },
            null, null, null);
    if (db_cursor.getCount() > 0) {
        db_cursor.moveToFirst();
        while (db_cursor.getPosition() != db_cursor.getCount()) {
            SimpleSyncFileModel simpleSyncFileModel = new SimpleSyncFileModel();
            simpleSyncFileModel.file_id =
                    Integer.toString(db_cursor.getInt(db_cursor.getColumnIndex("file_id")));
            simpleSyncFileModel.filenameWithPath =
                    db_cursor.getString(db_cursor.getColumnIndex("filenameWithPath"));
            result.add(simpleSyncFileModel);
            db_cursor.moveToNext();
        }
    }
    db_cursor.close();

    return result;
}

当我运行我的应用程序并尝试创建文件系统树时,我总是看到 java.lang.StackOverflowError:

FATAL EXCEPTION: Thread-23110
 java.lang.StackOverflowError
     at java.lang.ref.WeakReference.<init>(WeakReference.java:108)
     at java.util.WeakHashMap$Entry.<init>(WeakHashMap.java:71)
     at java.util.WeakHashMap.put(WeakHashMap.java:611)
     at android.database.sqlite.SQLiteConnectionPool.finishAcquireConnectionLocked(SQLiteConnectionPool.java:980)
     at android.database.sqlite.SQLiteConnectionPool.tryAcquirePrimaryConnectionLocked(SQLiteConnectionPool.java:916)
     at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:682)
     at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:400)
     at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:905)
     at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:586)
     at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
     at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
     at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
     at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1436)
     at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1283)
     at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1154)
     at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1322)
     at ru.rsit.megashare.managers.DBHelper.getSharedSimpleObjects(DBHelper.java:582)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:64)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
     at ru.rsit.megashare.models.global.SimpleSyncDirModel.addChilds(SimpleSyncDirModel.java:70)
    at

错误在这里:Cursor db_cursor = megashare_db.query

为什么会出现这个错误?当然我总是关闭光标。我需要做些什么来解决这个问题?

【问题讨论】:

  • 在开发递归查询时,请始终使用LIMIT 100 或任何您能想象到的最多结果数来创建安全网。这样,如果您错过了一些递归结束的特殊情况,您仍然可以获得有价值的调试信息。
  • @Yunnosch,我明白了。但是我有两个主要目录,其中的孩子数量不超过 80 件。对不起我的英语。
  • 这并不能保证 amok 递归保持少于 200 或 200000 个结果行。
  • 我现在将尝试再次跟踪此代码。也许这个递归永远不会结束。但我不这么认为
  • 我建议你通过调用addChilds(this) 来初始化递归,如果参数是nulladdChilds 不会做任何事情:if (targetObject == null) { return; } else { .... your code ... }。这样可以避免重复代码,如果getSharedSimpleObjects 返回一个包含null 的列表,也可以避免潜在的循环。

标签: java android sql sqlite recursion


【解决方案1】:

错误的原因是代码错误,我尝试在数据库目标目录中查找:此目录是否没有父目录。因此,如果我删除子对象,我的应用程序会复制一些目录。这就是递归要循环的原因。

【讨论】:

    猜你喜欢
    • 2013-02-25
    • 2022-11-03
    • 2016-08-23
    • 2011-12-09
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-22
    相关资源
    最近更新 更多