SQLite错误:数据库被锁定。

7

我正在编写的iPhone应用程序中使用了sqlite数据库。在后台线程中运行以下代码时,我遇到了一个错误。在后台线程中,我调用了这个方法:

 - (BOOL) songIsInDatabase:(NSString *)songTitle
{
NSString *docsDir;
NSArray *dirPaths;

dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];


//Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:@"Database.db"]];

const char *dbpath = [databasePath UTF8String];

sqlite3_stmt *statement;

if(sqlite3_open(dbpath, &DB) == SQLITE_OK){

    NSString *insertSQL = [NSString stringWithFormat:@"select * from Bpm_Table where song_title = '%@'", songTitle];

    const char *insert_stmt = [insertSQL UTF8String];
    if(sqlite3_prepare_v2(DB, insert_stmt, -1, &statement, NULL) == SQLITE_OK)
    {
        while (sqlite3_step(statement) == SQLITE_ROW)
        {
            return YES;
            break;
        }
    }else{
        NSLog(@"the error is %s", sqlite3_errmsg(DB));
    }
    sqlite3_finalize(statement); 
}

[databasePath release];
return NO;
}

然后我调用这个方法:

- (void) addSongToDatabase: (NSString *) songTitle andBPM: (int)bpm andGenre: (NSString *) genre
{
NSString *docsDir;
NSArray *dirPaths;

dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];


//Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:@"Database.db"]];

const char *dbpath = [databasePath UTF8String];

sqlite3_stmt *statement;

if(sqlite3_open(dbpath, &DB) == SQLITE_OK){

    NSString *insertSQL = [NSString stringWithFormat:@"insert or replace into Bpm_Table (song_title, bpm, genre) values (\"%@\", \"%d\", \"%@\")", songTitle, bpm, genre];

    const char *insert_stmt = [insertSQL UTF8String];
    if(sqlite3_prepare(DB, insert_stmt, -1, &statement, NULL) == SQLITE_OK){
        if(sqlite3_step(statement) == SQLITE_DONE)
        {

        } else {
            NSLog(@"error: %s", sqlite3_errmsg(DB));
        }
    }sqlite3_finalize(statement);
}

[databasePath release];
}

如果我依次运行这两种方法,就会出现一个错误,提示数据库已锁定。在谷歌上搜索后,我添加了sqlite3_finalize语句,希望能解决这个问题。如果我注释掉其中的任何一种方法,就不会出现这个错误。

有人知道是什么问题吗?

8个回答

12

在使用完sqlite数据库后,你必须始终关闭它 ... 因此,请在sqlite3_finalize(statement);后面加上这行代码sqlite3_close(DB);

更新 -

在你的while循环中有一处返回了YES -

        while (sqlite3_step(statement) == SQLITE_ROW)
        {
            return YES;
            break;
        }

所以你既没有完成也没有关闭数据库.. 如果每次打开它,你需要关闭它


6
但请注意,如果您从多个线程访问相同的SQLite数据库,而没有某种形式的分离同步(一些方法可知道您永远不会在多个线程中近乎同时进行访问),即使您在每次访问时都正确关闭了所有内容,您也可能会遇到“数据库已锁定”错误。
SQLite不提供任何形式的“等待锁定”机制。
您的基本选择是:
1.从一个线程中执行所有访问。
2.在所有访问周围使用单独的锁定协议。
3.如果您遇到“数据库已锁定”错误,请等待一段时间并重试。

这不是sqlite中的“锁等待”机制吗?http://www.sqlite.org/c3ref/busy_timeout.html - Dmitry Pashkevich
@DmitryPashkevich - 在标准的SQLite中,没有可靠的内置锁定机制。它们的目的纯粹是为了在代码错误的情况下保护数据库的完整性,并可能启用某种粗略的恢复。 - Hot Licks
我有点困惑。所以提到的功能不能正常工作?我不应该依赖它?但是它确实存在? - Dmitry Pashkevich
@DmitryPashkevich - 它做了它应该做的事情,即保护数据库并防止死锁。然而,对于一般情况来说,它不是足够的锁机制。特别是在处理事务时会遇到很多问题。 - Hot Licks

5

你的数据库是开着的,请使用sqlite3_close(db)关闭它。如果不关闭,访问数据库的进程将在后台运行,这会导致“数据库被锁定”错误。

如果您想消除“数据库被锁定”错误,请按照以下步骤操作: 1.将数据库文件复制到其他位置。 2.然后用复制的数据库替换原来的数据库。 3.这将取消引用正在访问您的数据库文件的所有进程。


我发现,即使没有关闭数据库,使用sqlite3_reset也能正常工作,不会出现数据库锁定错误。在每次准备后使用sqlite3_reset语句,以便重置已准备好的语句。这将解决您的数据库被锁定的错误。 - vinayak jadi

5
如果您尝试过sqlite3_close(DB),那么很可能是因为您的方法正在尝试同时访问同一个数据库。 请尝试将此行代码放置在适当的位置。
sqlite3_busy_timeout(DB, 500);

在你收到“数据库已锁定”错误消息的方法中,sqlite3_opensqlite3_prepare_v2之间的某个地方。

该方法中的数据库连接将在500毫秒内尝试写入/读取数据,如果失败就会放弃,这通常足以避免锁定。


3

您的数据库是开启状态。请使用sqlite3_close(db)关闭它。

如果不关闭,那么访问数据库的进程将在后台运行,这将导致数据库被锁定的错误发生。


0

我刚刚花了一个小时解决同样的问题。对我来说,问题出现在我无意中关闭了shell(当脚本正在运行while循环和计时器时),而db日志临时文件仍然打开。即使您在脚本中使用了db.close()或finalize,Windows也不会杀死进程,即使您已经在Python中杀死了它;如果您退出所有Python应用程序,任务管理器中仍将有一个正在运行。

因此,您需要在Windows任务管理器中结束所有Python进程,重新启动它们,这样就可以解决问题(如果实际上是问题的原因)。


0

首先,您在打开新连接之前没有使用sqlite3_close()关闭数据库连接


-3

我之前也遇到了同样的问题。我尝试复制数据库文件本身,将其重命名为不同的文件名,然后检查它 - 它实际上起作用了!

我正在使用SQLite3。

我希望这对你也有用!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接