我正在尝试在一个项目中使用sqlite数据库。

工作正常。但由于某种原因,发生了一些事情,但我找不到该错误。

resultSet对象总是从第一条记录之后退出。
数组中始终只有1条记录。 (可能由于错误而离开了一段时间)

我创建了一个DBManager类,该DBManager类包含不同的内部类。我有一个 private 的全局FMDatabase实例(在使用它之前,我将其初始化了)

如您所见,有2个不同的打印错误行

当我运行时,第二行显示此错误:

调用sqlite3_step时出错(21:内存不足)
错误域= FMDatabase代码= 7“内存不足” UserInfo = 0x790308d0 {NSLocalizedDescription =内存不足}


并且应该包含300条记录的数组中只有1条记录。
(最后打印行始终为1)

这部分看起来很简单。 (我在其他地方有完全相似的代码,但工作正常)

private var database : FMDatabase!

class DBManager{

    class Element{

        class func get()->[DataElement]{
            database.open()
            println( database.lastError() )

            var result = [DataElement]()

            var resultSet: FMResultSet! = database!.executeQuery("SELECT * FROM Element WHERE working = 1", withArgumentsInArray: nil)

            while resultSet.next(  ) {
                let data = DataElement(
                    id : Int(resultSet.intForColumn("id")),
                    name: resultSet.stringForColumn("name"),
                    server: resultSet.stringForColumn("server"),
                    working: resultSet.boolForColumn("working") )
                result.append( data )
            }

            println( database.lastError() )
            database.close()

            println( result.count )
            return result
        }
    }
}

PS:这些表之间的唯一区别是(据我所知)“id”列。此元素表具有一个“id” INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,但是另一个没有id列。但是他们两个长期以来都运作良好。

最佳答案

“内存不足”错误是一种误导性的SQLite错误,这意味着已使用NULL指针的sqlite3*值调用了SQLite函数。在FMDB中,这意味着您关闭了数据库,但随后尝试继续使用相同的FMDatabase实例(无需再次调用open)。
现在,在该代码示例中我看不到您这样做,但是此代码示例采用了一些可能导致这种错误的做法。即,不是在本地实例化FMDatabase对象,而是使用了database属性,并且冒着其他函数可能已经使用过它的风险(也许是initDataElement方法?也许是为了简洁起见而删除了其他功能?也许其他线程?)。
让我们想象一下,该函数调用了另一个函数来再次打开数据库(FMDB会自动让您这样做,如果数据库已经打开,则基本上会立即返回),执行一些SQL,然后关闭数据库,然后关闭该例程,去检索第二行信息,可能发现数据库已关闭,从而导致您描述的错误。数据库对象的打开和关闭不是递归的。子例程关闭后,它便完全关闭了。
现在所有这些都是假设性的,因为如果不看其余代码的工作,我将无法确认。但是,这种情况适合您共享的代码以及所描述的症状。
假设确实如此,这里有两种可能的解决方案:

  • 您只需打开数据库一次,然后将其保持打开状态,直到应用终止。这可能是最简单的方法,而且可能比这里的方法更有效。就提交单个SQL语句(或事务)而言,SQLite实际上非常健壮,因此人们通常使数据库保持开放状态。
    我什至可以更进一步,建议如果您可能有不同的线程与此数据库交互,请实例化一个FMDatabaseQueue对象,并在整个应用程序中使用该对象,而不是始终打开和关闭。请注意,如果您使用FMDatabaseQueue,那么您将更加明智地确保位于inDatabaseinTransaction块中间的一个函数不会调用试图执行另一个inDatabaseinTransaction块的另一个函数(或否则您将陷入僵局)。但是,就像任何共享资源一样,您希望对资源的锁定位置和释放时间保持敏感,数据库也不例外。
  • 如果您确定要按照此代码示例的建议在每个函数中打开和关闭数据库(再次,我不建议您这样做),则不要使用类属性来跟踪数据库。当然,有一些打开数据库的函数,但是返回此FMDatabase对象,每个函数都有其自己的本地实例,并在完成后关闭该实例。
    但是您确实想避免一个函数关闭数据库的意外后果影响其他某个函数的行为。
  • 关于ios - FMDB ResultSet始终仅返回一行,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29549753/

    10-10 22:22