Сделки iOS SQLite FMDB .. Правильное использование? - PullRequest
9 голосов
/ 05 июля 2011

Я просто собираюсь попробовать использовать транзакции с оболочкой FMDB SQLite для iOS.

Документация по транзакциям немного расплывчата, но, посмотрев несколько функций, я пришел к следующей логике:

[fmdb beginTransaction];
    // Run the following query
    BOOL res1 = [fmdb executeUpdate:@"query1"];
    BOOL res2 = [fmdb executeUpdate:@"query2"];

if(!res1 || !res2) [fmdb rollback];
else [fmdb commit];

Ответы [ 4 ]

18 голосов
/ 27 января 2013

Вы также можете использовать FMDatabaseQueue для обработки ваших транзакций, которая является частью fmdb:

[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];

    if (whoopsSomethingWrongHappened) {
        *rollback = YES;
        return;
    }
    // etc…
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];
}];

Документация

16 голосов
/ 05 июля 2011

Я бы не стал делать второе обновление, если первое не удалось.

bool ret = false;
[fmdb beginTransaction];
ret = [fmdb executeUpdate:@"query1"];
if (ret)
{
    ret = [fmdb executeUpdate:@"query2"];
    if (!ret)
    {
         // report error 2
    }
}

if(ret) 
{
    if (![fmdb commit])
    {
        // panic!
    }
}
else
{
    if (![fmdb rollback])
    {
        // panic!
    }
}

Для параноидальной устойчивости вы должны иметь блок try ... catch на случай, если что-нибудь выдаст исключение. Если вы это сделаете, вы можете использовать его в своих интересах.

[fmdb beginTransaction];
@try
{
    if (![fmdb executeUpdate:@"query1"])
    {
        // report error
        @throw someExcpetion;
    }
    if (![fmdb executeUpdate:@"query2"])
    {
        // report error
        @throw someExcpetion;
    }
    [fmdb commit]
}
@catch(NSException* e)
{
    [fmdb rollback];
    // rethrow if not one of the two exceptions above
}
4 голосов
/ 30 октября 2015

Быстрый путь:

let queue = FMDatabaseQueue(path: databaseURL.path!)

queue.inTransaction() {
    db, rollback in

    result = db.executeUpdate("INSERT INTO client VALUES (NULL, ?)", client.name ?? "")

    if result {
        client.ID = Int(db.lastInsertRowId())
    } else {
        rollback.initialize(true)
        print("\(__FUNCTION__) insert into table failed: \(db.lastErrorMessage())")
    }
}

queue.close()
1 голос
/ 05 июля 2011

Это похоже на действительный сценарий использования, к которому я мог бы добавить вывод значений -lastErrorMessage и -lastErrorCode перед выполнением отката, чтобы вы могли понять, что именно пошло не так.

Еще лучше делать эти вызовы после каждого -executeUpdate, чтобы вы знали, произошла ли ошибка после каждого оператора:

[fmdb beginTransaction];

// Run the following query
BOOL res1 = [fmdb executeUpdate:@"query1"];
if (!res1) {
   NSLog(@"Error %d - %@", [fmdb lastErrorMessage], [fmdb lastErrorCode]);
}

BOOL res2 = [fmdb executeUpdate:@"query2"];
if (!res2) {
   NSLog(@"Error %d - %@", [fmdb lastErrorMessage], [fmdb lastErrorCode]);
}

if(!res1 || !res2) [fmdb rollback];
else [fmdb commit];
...