Sqlite3 C++数据库锁定问题:修改记录时出现database is locked错误
解决SQLite "database is locked" 错误:未正确关闭数据库连接的问题
嘿,我一眼就揪出问题所在了——你的checkAvailability方法里有个典型的逻辑错误:return语句写在了资源释放代码的前面,导致数据库连接根本没被正常关闭,直接把数据库锁住了!
咱们仔细看这段出问题的代码:
if (sqlite3_step (stmt) == SQLITE_ROW) { return true; sqlite3_finalize (stmt); sqlite3_close (db); } else { return false; sqlite3_finalize (stmt); sqlite3_close (db); }
一旦执行return true或者return false,函数会立刻结束,后面的sqlite3_finalize(释放预处理语句)和sqlite3_close(关闭数据库连接)根本不会运行!这就意味着数据库连接一直处于打开状态,后续调用updateRecord尝试再次打开同一个数据库时,SQLite就会抛出"database is locked"错误。
另外,你在modifyBookRecords里还多调用了一次database.closeDb()——这其实是画蛇添足,而且如果checkAvailability已经出问题没关闭连接,这行代码也救不了,反而可能导致重复关闭的额外问题。
修复方案
首先,调整checkAvailability的代码顺序,确保不管查询结果如何,都先释放资源、关闭数据库,再返回结果:
bool Database::checkAvailability(std::string& input) { openDb(dir); sqlite3_stmt* stmt = nullptr; rc = sqlite3_prepare_v2(db, "SELECT * FROM Books WHERE Title = ? OR Isbn = ?", -1, &stmt, NULL); if (rc != SQLITE_OK) { std::cout << sqlite3_errmsg(db); sqlite3_close(db); // 出错时也要确保关闭数据库 return false; } sqlite3_bind_text(stmt, 1, input.c_str(), input.length(), NULL); sqlite3_bind_text(stmt, 2, input.c_str(), input.length(), NULL); // 先把查询结果存起来 bool recordExists = (sqlite3_step(stmt) == SQLITE_ROW); // 必须先释放预处理语句,再关闭数据库 sqlite3_finalize(stmt); sqlite3_close(db); return recordExists; }
然后,修改modifyBookRecords,去掉那个多余的closeDb调用:
void Bookshop::modifyBookRecords () { std::cout << "You want to modify a book" << std::endl; std::cout << "Title/ISBN: "; std::string input; std::getline (std::cin, input); bool isAvailable = database.checkAvailability (input); // 删掉这行!checkAvailability内部已经关闭了数据库 // database.closeDb (); if (isAvailable) { std::cout << "Title: "; std::string title; std::getline (std::cin, title); std::cout << "Author: "; std::string author; std::getline (std::cin, author); std::cout << "Pages: "; int pages; std::cin >> pages; std::cin.ignore (std::numeric_limits<std::streamsize>::max (), '\n'); std::cout << "Genre: "; std::string genre; std::getline (std::cin, genre); std::cout << "Publisher: "; std::string publisher; std::getline (std::cin, publisher); std::cout << "ISBN: "; std::string isbn; std::getline (std::cin, isbn); std::cout << "Number of Copies: "; int numberOfCopies; std::cin >> numberOfCopies; std::cin.ignore (std::numeric_limits<std::streamsize>::max (), '\n'); database.updateRecord (input, title, author, pages, genre, publisher, isbn, numberOfCopies); } else { std::cout << "The book was not found" << std::endl; } }
额外建议
为了避免以后再犯类似的错误,你可以考虑用**RAII(资源获取即初始化)**的方式来管理SQLite的连接和预处理语句——比如写个简单的封装类,在构造函数里打开连接/创建stmt,析构函数里自动释放资源,这样就不用手动记着调用close和finalize了,能大幅减少这类资源泄漏的问题。
内容的提问来源于stack exchange,提问作者Noctera
相关产品推荐
相关产品推荐

