快速递归地在数据库中插入和更新数据时面临内存问题

Posted

技术标签:

【中文标题】快速递归地在数据库中插入和更新数据时面临内存问题【英文标题】:Facing memory issue while Recursively inserting and updating data in database in swift 【发布时间】:2016-12-28 10:39:10 【问题描述】:

我正在数据库中插入和更新超过 100000 个数据。我正在使用 libsqlite3 框架。

问题:我面临的是每次插入内存增加到 4-5 mb 并且永远不会被释放。有更好的解决方案吗?

class DataBase

let COMPANY_TABLE_NAME = "CompanyTable"

let fileName = "\(Constants.sharedInstance.DATABASE_NAME).sqlite"
let DBPath :String?

init() 

  DBPath  = FileManagement.sharedInstance.getDocumentFilePath(fileName)


private var dbPointer: OpaquePointer?

  let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
  let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)



deinit

    sqlite3_close(dbPointer)



  func openDataBase(dbPath:String) -> OpaquePointer 


    var db: OpaquePointer?

    if sqlite3_open(dbPath, &db) == SQLITE_OK
    
        print("Successfully opened connection to database at \(dbPath)")
    
    else
    
        //call to load database from file system
    
    return db!



func inserttoCompanyTable(org_code: String , dataString:String)



    let insertSql = "INSERT INTO CompanyTable(orgcode,company_data) VALUES (?,?)"

    let insertStatement = prepareStatement(sql: insertSql)

    sqlite3_bind_text(insertStatement, 0, org_code, -1, SQLITE_TRANSIENT)
    sqlite3_bind_text(insertStatement, 1, dataString, -1,SQLITE_TRANSIENT)


    if sqlite3_step(insertStatement) != SQLITE_DONE 

        let errmsg = String(cString: sqlite3_errmsg(insertStatement))
        print("failure inserting foo: \(errmsg)")
    

    sqlite3_finalize(insertStatement)
    sqlite3_close_v2(insertStatement)



func readAllData()-> [Company]


    var companiesArray:[Company] = [Company]()
    let selectQuery = "SELECT * FROM \(COMPANY_TABLE_NAME);"
    let selectStatement = prepareStatement(sql: selectQuery)

    while sqlite3_step(selectStatement) == SQLITE_ROW 

       if let comStr = sqlite3_column_text(selectStatement, 1)
       
        let comString = String(describing: comStr)

        let comOBj = Mapper<Company>().map(JSONString: comString)
        companiesArray.append(comOBj!)
       

    

    return companiesArray



func isCompanyAvailable(org_code:String) -> Bool 



    let selectQuery = "SELECT * FROM \(COMPANY_TABLE_NAME) WHERE \(CompanyTable.orgcode) =?;"
    let selectStatement = prepareStatement(sql: selectQuery)

    sqlite3_bind_text(selectStatement, 0, org_code, -1, SQLITE_TRANSIENT)

    if sqlite3_step(selectStatement) == SQLITE_ROW
    
        return true
    
    else
    
        return false
    



 


func updateTableData(company: Company)-> Bool  

    let objString = company.toJSONString()
    let updateQuery = "UPDATE TABLE \(COMPANY_TABLE_NAME) SET \(CompanyTable.company_data) = \(objString) WHERE \(CompanyTable.orgcode) = \(company.orgCode);"
    let updateStatement = prepareStatement(sql: updateQuery)

    if sqlite3_step(updateStatement) == SQLITE_ROW
    
        return true
    
    else
    
        return false
    




func deleteFromCompanyTable(company:Company) 

     let deleteQuery = "DELETE FROM \(COMPANY_TABLE_NAME) WHERE \(CompanyTable.orgcode) = \(company.orgCode);"
    let deleteStatement = prepareStatement(sql: deleteQuery)

    if sqlite3_step(deleteStatement) == SQLITE_DONE
    
        print("Successfully deleted row.")
     else 

        print("Could not delete row.")
     



func prepareStatement(sql: String) -> OpaquePointer 
    var statement: OpaquePointer?


    if sqlite3_open(DBPath, &self.dbPointer) == SQLITE_OK
    
        print("Successfully opened connection to database at \(DBPath)")
        if sqlite3_prepare_v2(self.dbPointer, sql, -1, &statement, nil) == SQLITE_OK
        

            return statement!
        
        else
        
            let errmsg = String(cString: sqlite3_errmsg(statement))
            print("error preparing select: \(errmsg)")
        
    


    return statement!

【问题讨论】:

顺便说一句,在您正确调用sqlite3_finalize 的地方,即在inserttoCompanyTable 中,您也使用该语句调用sqlite3_close_v2,这是不正确的。你不应该“关闭”一个声明。只需“完成”它,您就完成了该声明。我们关闭数据库,而不是语句。 还要记住,sqlite3_bind_XXX 调用采用从 1 开始的索引,而不是从 0 开始的索引。 sqlite3_column_XXX 调用使用从零开始的索引,但不是 sqlite3_bind_XXX API。 【参考方案1】:

您将泄漏内存,因为您的大多数sqlite3_prepare_v2 调用没有跟随相应的sqlite3_finalize 调用。每次成功准备 SQL 语句时,都必须确保在完成该语句后完成该语句。

【讨论】:

以上是关于快速递归地在数据库中插入和更新数据时面临内存问题的主要内容,如果未能解决你的问题,请参考以下文章

关于SQL数据库批量更新和增加的问题。

SQL Server 2008:插入不完整的数据并更新它

一次快速将多个图像保存到文件系统,高CPU

如何最有效地在 SQL Server 中插入/更新几百万行?

java ehcache

递归地在不同的 xsl 文件中添加一行行