在仍然访问其他表时创建临时表

时间:2015-06-20 07:48:03

标签: c++ sqlite temp-tables

我有两个或更多数据库连接到一个SQLite数据库连接。每个数据库由3个表组成。为了更好地访问搜索/过滤,我在所有表和数据库上创建了一个巨大的临时表,如下所示:

"CREATE TEMPORARY TABLE temp_table AS "
   "SELECT * FROM pb.name_table " 
      "LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
      "LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
   "UNION SELECT * FROM name_table " \<br>
      "LEFT JOIN phone_table ON (name_table.id=phone_table.id) " \
      "LEFT JOIN email_table ON (name_table.id=email_table.id);";

如果表中的内容发生了变化,我必须重新创建临时表。
随着数据量的增加,创建临时表需要一些时间,但由于我对表有持续的读访问权,我的想法如下:

  1. 创建一个线程,在后台创建第二个临时表
  2. 阻止阅读客户端访问
  3. DROP第一个临时表
  4. 重命名第二个临时表
  5. 现在的问题是:创建临时表是对数据库的写访问权限,它也会自动阻止所有读取线程。

    有谁知道如何处理这个问题?我在重新创建临时表时需要读访问权。

2 个答案:

答案 0 :(得分:0)

只要所有线程都是同一程序的一部分,您就可以控制所有数据库连接。 因此,您可以在完全独立的数据库中编写数据,并且ATTACH很快就可以了。

答案 1 :(得分:0)

非常感谢您的回答。我更改了我的代码并发现我需要在工作线程中使用新的数据库连接(sqlite3_open)来阻止其他线程。也无法在附加的“临时数据库”中创建TEMPORARY TABLE,因为创建临时表不允许使用限定符(例如:x.temp_table),因此我必须创建一个真正的表,其中消耗了大量内存我们的flash文件系统(不允许)。
可是等等!我有个主意 (2小时后)
我做的!我打开一个空数据库并将相关数据库附加到连接。我在空数据库中创建了一个临时表,它在flash中不占用内存,因为它是临时的 当我必须创建一个新表时,我打开另一个空数据库并将相关数据库附加到连接。操作完成后,我切换旧连接和新连接。代码如下:

    #include <iostream>
    #include "dbAccess.h"
    #include <cstdio>
    #include <string>
    #include <cstring>

    using namespace std;

    bool inProgress = true;

    DWORD WINAPI createTempTableThread(void *param);

    int callback(void *NotUsed, int argc, char **argv, char **azColName)
    {
        cout << "*";
        return 0;
    }

    int main(void)
    {
        sqlite3* db = NULL;
        HANDLE hThreadHandle = NULL;
        CdbAccess *dba = new CdbAccess();
        int i = 0;
        db = dba->dbaConnect();
        dba->dbaSetDatabase(db);

        cout << "INFO: Creating initial temporary table. " << endl;
        sqlite3_exec(dba->dbaGetDatabase(), "CREATE TEMPORARY TABLE temp_table AS " \
                   "SELECT * FROM pb.name_table " \
                      "LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
                      "LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
                   "UNION SELECT * FROM intern.name_table " \
                      "LEFT JOIN intern.phone_table ON (intern.name_table.id=intern.phone_table.id) " \
                      "LEFT JOIN intern.email_table ON (intern.name_table.id=email_intern.table.id);", NULL, NULL, NULL);
        cout << "INFO: Creating initial temporary table finished. " << endl;

        while(1)
        {
            hThreadHandle = CreateThread(0, 0, createTempTableThread, dba, 0, 0);

            while(inProgress)
            {
            sqlite3_exec(dba->dbaGetDatabase(), "SELECT * FROM name_table WHERE id LIKE 1;", callback, NULL, NULL);
            }

            for(i = 0; i < 5; i++)
            {
                sqlite3_exec(dba->dbaGetDatabase(), "SELECT * FROM name_table WHERE id LIKE 2;", callback, NULL, NULL);
            }

            inProgress = true;

            CloseHandle(hThreadHandle);
        }


        dba->dbaDisconnect();

        return 0;
    }


CdbAccess::CdbAccess()
{
    hSemaphore = CreateSemaphore(NULL, 1, 1, 0);
}

CdbAccess::~CdbAccess()
{
}

sqlite3 *CdbAccess::dbaConnect()
{
    sqlite3 *db;
    static int num = 1;
    int err = SQLITE_OK;
    string attach = "ATTACH DATABASE \"";
    string internal = "cbInternal.db";

    if(num == 1)
    {
        cout << endl << "INFO: cbTemp1.db";
        err = sqlite3_open("cbTemp1.db", &db);
        num = 2;
    }
    else
    {
        cout << endl << "INFO: cbTemp2.db";
        err = sqlite3_open("cbTemp2.db", &db);
        num = 1;
    }

    if(err == SQLITE_OK)
    {
        cout << endl << "INFO: Temp database opened.";
        err = sqlite3_exec(db, "ATTACH DATABASE \"cbInternal.db\" AS intern;", NULL, NULL, NULL);
        if(err == SQLITE_OK)
        {
            cout << endl << "INFO: Internal database attached.";

            err = sqlite3_exec(db, "ATTACH DATABASE \"0123456789.db\" AS pb;", NULL, NULL, NULL);
            if(err == SQLITE_OK)
            {
                cout << endl << "INFO: Phone book attached.";
            }
            else
            {
                cout << endl << "ERROR: Attaching phone book: " << sqlite3_errmsg(db);
            }
        }
        else
        {
            cout << endl << "ERROR: Attaching internal database: " << sqlite3_errmsg(db);
        }
    }
    else
    {
        cout << endl << "ERROR: Opening database: " << sqlite3_errmsg(db);
    }

    return db;
}

int CdbAccess::dbaDisconnect(void)
{
    int err = SQLITE_OK;

    err = sqlite3_exec(db, "DETACH DATABASE pb;", NULL, NULL, NULL);
    if(err == SQLITE_OK)
    {
        cout << endl << "INFO: Phone book detached.";
        err = sqlite3_exec(db, "DETACH DATABASE intern;", NULL, NULL, NULL);
        if(err == SQLITE_OK)
        {
            cout << endl << "INFO: Internal database detached.";
            err = sqlite3_close(db);
            if(err == SQLITE_OK)
            {
                cout << endl << "INFO: Database connection closed.";
            }
            else
            {
                cout << endl << "ERROR: Could not close database: " << sqlite3_errmsg(db);
            }
        }
        else
        {
            cout << endl << "ERROR: Could not detach internal database: " << sqlite3_errmsg(db);
        }
    }
    else
    {
        cout << endl << "ERROR: Could not detach phone book: " << sqlite3_errmsg(db);
    }

    return err;
}

sqlite3* CdbAccess::dbaGetDatabase(void)
{
    return db;
}

void CdbAccess::dbaSetDatabase(sqlite3 * sqldb)
{
    db = sqldb;
}

int CdbAccess::dbaGetTempTableAccess(void)
{
    cout << endl << "INFO: Access requested.";
    WaitForSingleObject(hSemaphore, INFINITE);
    return 0;
}

int CdbAccess::dbaReleaseTempTableAccess(void)
{
    cout << endl << "INFO: Access released.";
    ReleaseSemaphore(hSemaphore, 1, NULL);
    return 0;
}


DWORD WINAPI createTempTableThread(void *param)
{
    int err = SQLITE_OK;
    CdbAccess *d = (CdbAccess *)param;
    sqlite3 *db;

    cout << endl << "INFO: createTempTable: IN";

    inProgress = true; // global variable for test porpose only

    db = d->dbaConnect();

    if(db != NULL)
    {
        cout << endl << "Thread: INFO: Creating temporary table. ";
        err = sqlite3_exec(db, "CREATE TEMPORARY TABLE temp_table AS " \
                   "SELECT * FROM pb.name_table " \
                      "LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
                      "LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
                   "UNION SELECT * FROM intern.name_table " \
                      "LEFT JOIN intern.phone_table ON (intern.name_table.id=intern.phone_table.id) " \
                      "LEFT JOIN intern.email_table ON (intern.name_table.id=intern.email_table.id);", NULL, NULL, NULL);
    }

    if(err != SQLITE_OK)
    {
        cout << endl << "Thread: ERROR: Creating temporary table: " << sqlite3_errmsg(db);
    }
    else
    {
        cout << endl << "Thread: INFO: Creating temporary table finished. ";
    }

    d->dbaSetDatabase(db);

    inProgress = false; // global variable for test porpose only

    cout << endl << "Thread: INFO: createTempTable: OUT";

    return 0;
}