Using transactions to insert is throwing errors Sq

2019-05-24 03:07发布

问题:

I have created a Database class as so:

class Database {
    static let instance = Database()
    private let categories = Table("Category")
    private var db: Connection?

    let cat_id = Expression<String>("id")
    let cat_name = Expression<String>("name")


    private init() {
        let path = NSSearchPathForDirectoriesInDomains(
            .documentDirectory, .userDomainMask, true
            ).first!
        do {
            db = try Connection("\(path)/SalesPresenterDatabase.sqlite3")
            createTable()
        } catch {
            print("error")
        }
    }
    func createTable() {
        do{
            try self.db!.run(self.categories.create(ifNotExists: true) { table in
                table.column(self.cat_id)
                table.column(self.cat_name)
            })
        }catch{
             print("error")
        }
    }

    func addRow(table: DBTableNames, object: [Any]) -> Int64? {
      do {
         try self.db!.transaction() {
            for obj in object{
                if table.rawValue == DBTableNames.Category.rawValue{
                    let cats : CategoryObject = obj as! CategoryObject
                    let insert = self.categories.insert(self.cat_id <- cats.id,
                                                        self.cat_name <- cats.name)
                    try self.db!.run(insert)

                }
             }
          }
        }catch{
           print("Insert failed \(error)")
           return -1
        }
        return 1
         }
}

I then go on to call my code to add a row by running the following:

    let returnValue = Database.instance.addRow(table: DBTableNames(rawValue: entity)!,
                                               object: databaseObject)

The problem I have is that it always throws an error saying:

Insert failed The operation couldn’t be completed. (SQLite.Result error 0.) and full: cannot rollback - no transaction is active (code: 1)

If I see this error one more time my Mac will be going out of the window!

The whole operation is in a background thread but I have tried the following as well:

    DispatchQueue.main.async{
    let returnValue = Database.instance.addRow(table: DBTableNames(rawValue: entity)!,
                                                   object: databaseObject)
}

It didn't work. It doesn't make sense as I also tried creating the tables in a transaction and that worked perfectly.

Any help would be greatly appreciated!

回答1:

Your func createTable() and func addRow() methods are not thread safe. Multiple threads can access it at the same time.

Create a private serial DispatchQueue inside your Singleton class and do above functions through this serial queue. This will prevent accessing the database from several threads at the same time, and serial queue will queue concurrent tasks.