FMDB ResultSet始终只返回一行

时间:2015-04-09 21:55:36

标签: ios swift resultset fmdb

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

工作正常;但出于某种原因,发生了一些事情,我无法找到那个错误。

resultSet对象始终在第一条记录之后退出。 数组中总是只有1条记录。(可能因为错误而遗留下来)

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

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

当我跑步时,第二条打印线会出现此错误:

调用sqlite3_step(21:内存不足)rs时出错 错误域= 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列。但是他们两人都工作了很长时间。

2 个答案:

答案 0 :(得分:2)

“内存不足”错误是一种误导性的SQLite错误,这意味着使用NULL指针的sqlite3*值调用SQLite函数。在FMDB中,这意味着您关闭了数据库,但之后尝试继续使用相同的FMDatabase实例(不再调用open)。

现在,我没有看到你在这个代码示例中这样做,但是这个代码示例正在采用一些使这种错误成为可能的做法。也就是说,不是在本地实例化FMDatabase对象,而是使用一些database属性,并且存在其他一些函数可能使用它的风险(可能是init DataElement方法为了简洁起见,你可能删除了一些其他功能?也许是其他一些线程?)。

让我们假设这个函数调用了一些其他函数再次打开数据库(FMDB会默默地让你做,基本上如果数据库已经打开就立即返回),执行一些SQL,然后关闭数据库,然后这个例程当它去检索第二行信息时,会发现数据库已关闭,导致您描述的错误。数据库对象的打开和关闭不是递归的。一旦子程序关闭它,它就完全关闭了。

现在所有这些都是假设的,因为没有看到你的其余代码所做的事情,我无法确认。但它的场景适合您所分享的代码以及您所描述的症状。

假设情况确实如此,这里有两种可能的解决方案:

  1. 您只需打开数据库一次,然后将其保持打开状态,直到应用程序终止。这可能是最简单的方法,可能比你在这里有效。 SQLite在提交单个SQL语句(或事务)方面实际上非常强大,因此人们通常会打开数据库。

    我甚至可能更进一步,并建议如果你可能有不同的线程与这个数据库交互,你实例化一个FMDatabaseQueue对象,并在整个应用程序中使用它,再次不打开和关闭所有时间。请注意,如果您使用FMDatabaseQueue,那么您需要更加明智地确保位于inDatabaseinTransaction块中间的一个函数不会调用另一个函数尝试执行另一个inDatabaseinTransaction阻止的函数(否则您将死锁)。但是,与任何共享资源一样,您希望对资源被锁定的位置以及资源何时发布敏感,并且数据库也不例外。

  2. 如果您决定在每个函数中打开和关闭数据库,例如此代码示例建议(再次,我不建议这样做),那么不要使用类属性来跟踪数据库。当然,有一些函数可以打开数据库,但返回这个FMDatabase对象,每个函数都有自己的本地实例,并在完成后关闭该实例。

    但是你真的想避免一个函数关闭数据库影响其他函数行为的意外后果。

答案 1 :(得分:0)

我也遇到了同样的问题,因为从表中删除记录后我关闭了连接,经过一段时间后我又调用了一个sql查询,在那个时候我遇到了同样的问题

“FMDatabase Code = 7”内存不足“UserInfo = 0x790308d0 {NSLocalizedDescription =内存不足}”

在关闭连接之前只需添加一行代码,即。,

database = nil database.close()

稍后在模态类中添加方法,如下所示

func openDatabase() -> Bool {
    if database == nil {            
        if !FileManager.default.fileExists(atPath: pathToDatabase) {                
            let documentsDirectory = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString) as String
            pathToDatabase = documentsDirectory.appending("/\(databaseFileName)")
            print(pathToDatabase)              
           }
         database = FMDatabase(path: pathToDatabase)
    }           
    if !database.isOpen {
        database.open()
    }
    return true
}

在执行任何查询之前,请检查

if openDatabase() {
//Query
}

它解决了我的问题。