iOS sqlcipher fmdb inTransaction“文件已加密或不是数据库”

时间:2015-11-02 09:03:32

标签: ios objective-c encryption fmdb

当我使用sqlcipher加密我的数据库,并在FMDatabaseQueue中调用inDatabase - 成功!

但是当我将inDatabase更改为inTransaction时,控制台会显示“文件已加密或不是数据库”。

代码:

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:st_dbPath];

// success
[queue inDatabase:^(FMDatabase *db) {

    [db setKey:st_dbKey];
    [db executeUpdate:@"INSERT INTO t_user VALUES (16)"];
}];

// fail : File is encrypted or is not a database
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {

    [db setKey:st_dbKey];
    [db executeUpdate:@"INSERT INTO t_user VALUES (17)"];
}];

加密数据库代码:

NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
NSString *ecDB = [documentDir stringByAppendingPathComponent:st_dbEncryptedName];

// SQL Query. NOTE THAT DATABASE IS THE FULL PATH NOT ONLY THE NAME
const char* sqlQ = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS encrypted KEY '%@';", ecDB, st_dbKey] UTF8String];

sqlite3 *unencrypted_DB;
if (sqlite3_open([st_dbPath UTF8String], &unencrypted_DB) == SQLITE_OK) {

    // Attach empty encrypted database to unencrypted database
    sqlite3_exec(unencrypted_DB, sqlQ, NULL, NULL, NULL);

    // export database
    sqlite3_exec(unencrypted_DB, "SELECT sqlcipher_export('encrypted');", NULL, NULL, NULL);

    // Detach encrypted database
    sqlite3_exec(unencrypted_DB, "DETACH DATABASE encrypted;", NULL, NULL, NULL);

    sqlite3_close(unencrypted_DB);
}
else {
    sqlite3_close(unencrypted_DB);
    NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(unencrypted_DB));
}

加密代码来自那里:http://www.guilmo.com/fmdb-with-sqlcipher-tutorial/

2 个答案:

答案 0 :(得分:3)

调用inTransaction会导致在调用完成块之前在数据库上执行SQL语句begin exclusive transaction。因此,在您有机会调用setKey之前执行SQL。

您可以改为使用inDatabase并在传回的FBDatabase实例上调用beginTransaction,如下所示:

[self.queue inDatabase:^(FMDatabase *db) {

    [db setKey:st_dbKey];
    [db beginTransaction];

    [db executeUpdate:@"INSERT INTO t_user VALUES (17)"];

    [db commit];
}];

答案 1 :(得分:1)

Gus Hovland的答案有效,但我认为更好的方法是将inTransaction:更改为inDeferredTransaction:。从FMDB的inTransaction文档中:

”与SQLite的BEGIN TRANSACTION不同,此方法当前执行              排他性交易,而不是延期交易。这种行为              在将来的FMDB版本中可能会发生变化,因此此方法              最终可能会采用标准的SQLite行为并执行              延期交易。如果您真的需要独家交易,那就是              建议您不仅使用inExclusiveTransaction              使您的意图明确,同时也使您的代码适应未来。”