【问题标题】:C++ SQLite Serialized Mode QuestionsC++ SQLite 序列化模式问题
【发布时间】:2016-07-12 20:35:26
【问题描述】:

我已经浏览了相当多的页面,并且对它的想法有一个很好的想法,但我有几个问题只是为了确定......

我的程序使用 -DTHREADSAFE=1 编译选项,在从用户或我的网络接收数据库请求(选择、删除、插入、更新)时分叉,然后子进程处理各种数据库任务,并中继消息如果需要,等等,

目前我的数据库没有为并发设置,我不会说谎是一个主要的设计缺陷,但目前这不是重点,假设我有一个函数可以打印我的表 LEDGER 中的所有条目,如下所示。 ..

void PersonalDataBase::printAllEntries()
{
//get all entries
const char query [] = "select * from LEDGER";
sqlite3_stmt *stmt;
int error

try
{
    if ((error = sqlite3_prepare(publicDB, query, -1, &stmt, 0 )) == SQLITE_OK)
    {
        int ctotal = sqlite3_column_count(stmt);
        int res = 0;

        while ( 1 )         
        {
                res = sqlite3_step(stmt);

                if ( res == SQLITE_ROW ) 
                {
                    Entry *temp = loadBlockRow(stmt);

                    string from, to;
                    from = getNameForHash(temp -> from);
                    to = getNameForHash(temp -> to);

                    temp -> setFromOrTo(from, 0);
                    temp -> setFromOrTo(to, 1);

                    temp -> printEntry();
                    printlnEnd();
                    delete temp;
                }
                else if ( res == SQLITE_DONE || res==SQLITE_ERROR)    
                {
                    if (res == SQLITE_ERROR) { throw res; }
                    sqlite3_finalize(stmt);
                    break;
                }    
        }
    }
    //problems
    else
    {
        throw error;
    }
}
catch (int err)
{
    sqlite3_finalize(stmt);
    setupOutput();
    cout << "Database Error: " << sqlite3_errmsg(publicDB) << ", Error Code: " << (int) error << endl;
    cout << "Did Not Find Values Try Again After Fixing Problems Above." << endl;   
    printlnEnd();
}
println("Done!");
}
  • 我的 setupOutput()、printlnEnd()、println(),所有这些都有助于我使用“非阻塞”键盘输入/输出,它们可以按我的意愿工作,在这里不用担心它们,把它们想象成打电话给 cout

好的,所以现在我认为有 4 个选项...

  1. 在我的 try/catch 附近,然后在 catch 检查 err = 5,如果是,我需要设置一个 sqlite3_busy_handler 并让它等待任何阻塞当前操作的东西(一旦它返回 SQLITE_OK 并已清理把我所有的旧变量都重复一遍/再试一次),现在因为一次只能设置其中一个,比如说 Child1 正在做一个大写,而 child2 和 child3 正试图同时说读取和更新在第一个孩子的写入之上,所以如果这个函数返回一个 SQLITE_BUSY 我打印出一个错误,然后重新启动我的 while 循环(重新启动函数),当然在我完成了我的旧语句并清除了任何本地对象之后如果这是正确的思路,可能已经创建了?

  2. 我是否应该设置一个递归互斥锁,比如将其拧到 SQLite 自己的锁定机制上,将其设置为跨进程共享,然后一次只允许对数据库进行一项操作?对于在小范围内使用我的应用程序,这似乎不是一个坏的选择,但是我正在阅读很多关于使用递归互斥锁的警告,并且想知道这是否是最好的选择,因为许多帖子都说处理相互排斥自己。但是我不能同时读取,这有点痛苦

  3. 使用选项 1,但不使用 SQLite 繁忙处理程序,只需对随机数调用 usleep,清理数据,然后重新启动?

  4. 在涉及我的数据库的任何函数之前/之后分别使用带有“BEGIN IMMEDIATE”/“COMMIT”的 sqlite3_exec(),在这两个语句之间的代码持续时间内锁定数据库。因此,任何包含在里面的东西都不能(或至少应该)返回 SQLITE_BUSY,然后如果我的“BEGIN IMMEDIATE”返回 BUSY(只要一切设置正确,它应该是唯一的),我使用 sqlite3_busy_handler 老实说,如果只是一个进程一次可以使用它似乎很烦人......或者使用 usleep() 的随机数,(大概在这个数字相当大 1mil = 1 秒时,1-20 个进程之间重叠的机会非常小)所以每个进程会为了自己的目的不断尝试以随机间隔重新锁定数据库

  5. 有没有更好的方法?或者其中哪一个是最好的?

【问题讨论】:

    标签: c++ multithreading sqlite mutex


    【解决方案1】:

    SQLite 的内部繁忙处理程序(与sqlite3_busy_timeout() 一起安装)已经或多或少地休眠了随机次数;无需编写自己的处理程序。

    使用您自己的锁定机制会比随机等待更有效,但前提是您有读取器/写入器锁。

    BEGIN 或 BEGIN IMMEDIATE 确保同一事务中的任何其他语句都不会遇到锁,但前提是 IMMEDIATE 用于写入的事务。

    要允许并发读取器和写入器,请考虑使用WAL mode。 (但这也不允许多个作家。)

    【讨论】:

    • 但是如果 2 个进程“碰撞”都调用 sqlite3_busy_timeout(),那么如果我没记错的话,原始调用者将返回 SQLITE_BUSY,那么我是否必须创建一个处理程序来处理它?好的,所以当我修改数据时只使用 IMMEDIATE 关键字?这里的问题是,如果 somone 当前正在读取行,而另一个进程决定调用 IMMEDIATE,将立即是 SQLITE_BUSY,直到读取器完成,或者它会停止我的读取?好像它停止了我的数据读取/打印,那么老实说,即使是读取事务也最好锁定
    • 您可以使用sqlite3 命令行shell(也有.timeout)来测试立即锁定。
    • 太棒了!我最终使用 WAL 模式和一个递归互斥锁来写入/删除/等到数据库,现在似乎一切正常!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多