2010-03-12 67 views
5

我正在开发一个使用SQLite3数据库存储数据的Visual C++应用程序。通常它大部分时间都在托盘中。SQLite文件锁定和DropBox

我也想启用将我的应用程序放入DropBox文件夹以在多台PC上共享。 直到DropBox最近更新自己以前,它工作得非常好。 现在它说它“无法同步正在使用的文件”。 SQLite文件在我的应用程序中打开,但锁是共享的。有一些准备好的陈述,但是在使用step后立即重置。

有什么办法可以同步打开的SQLite数据库文件吗?谢谢!

下面是简单的包装,我使用只是为了测试(没有错误处理)的情况下,这有助于:

class Statement 
{ 
private: 
    Statement(sqlite3* db, const std::wstring& sql) : db(db) 
    { 
    sqlite3_prepare16_v2(db, sql.c_str(), sql.length() * sizeof(wchar_t), &stmt, NULL); 
    } 

public: 
    ~Statement() { sqlite3_finalize(stmt); } 

public: 
    void reset() { sqlite3_reset(stmt); } 
    int step() { return sqlite3_step(stmt); } 
    int getInt(int i) const { return sqlite3_column_int(stmt, i); } 

    std::wstring getText(int i) const 
    { 
    const wchar_t* v = (const wchar_t*)sqlite3_column_text16(stmt, i); 
    int sz = sqlite3_column_bytes16(stmt, i)/sizeof(wchar_t); 
    return std::wstring(v, v + sz); 
    } 

private: 
    friend class Database; 

    sqlite3* db; 
    sqlite3_stmt* stmt; 
}; 


class Database 
{ 
public: 
    Database(const std::wstring& filename = L"")) : db(NULL) 
    { 
    sqlite3_open16(filename.c_str(), &db); 
    } 

    ~Database() { sqlite3_close(db); } 

    void exec(const std::wstring& sql) 
    { 
    auto_ptr<Statement> st(prepare(sql)); 
    st->step(); 
    } 

    auto_ptr<Statement> prepare(const std::wstring& sql) const 
    { 
    return auto_ptr<Statement>(new Statement(db, sql)); 
    } 

private: 
    sqlite3* db; 
}; 

UPD:试了注释掉sqlite3.c到与LockFile和LockFileEx所有呼叫 - 相同的结果。

UPD2:试图在闲置时调用sqlite3_close(就像概念验证一样) - 仍然是相同的结果! Filemon告诉该文件仍然没有关闭,只能解锁。

UPD3:自动提交模式开启。 BEGIN和COMMIT的数量相符(类交易和RAII负责)。 SQliteManager能够在我的应用程序运行时连接到数据库并对其进行修改。

+1

您是否检查sqlite3_close()的结果?也许这不起作用,因为你还没有完成所有你准备好的陈述。 – 2010-03-15 12:57:32

+0

就是这样!由于正在运行的后台备份,它无法工作。愚蠢的错误..谢谢!把它作为答案,我会接受它。 – 2010-03-16 08:45:16

回答

4

检查sqlite3_close()的结果。也许这不起作用,因为你还没有完成所有你准备好的陈述。

2

你在使用什么文件系统?

您确定autocommit已开启和/或您是否提交了您的陈述吗?我记得有一个没有提交的问题,锁会保持不变。

+0

NTFS。关于提交的好主意,谢谢,我会检查这是否可能。 – 2010-03-14 08:47:06

+0

自动提交模式开启。 BEGIN和COMMIT的数量相符(类交易和RAII负责)。似乎这不是原因。 SQliteManager能够在我的应用程序运行时连接到数据库并对其进行修改。 – 2010-03-14 09:14:17

2

Alex Pechnikov有一个多主SQLite数据库复制程序sqlite3-rdiff。对于你正在努力完成的任务来说,这可能是矫枉过正的,但它可能比文件复制更容易。

SQLite也有Online Backup API;该页面上有一个示例:示例2:正在运行的数据库的联机备份。

+0

我想不出如何自动使用它。 sqlite3-rdiff需要Tcl,并且使用备份API意味着在每次更改后复制整个数据库。 – 2010-03-15 08:11:01

+0

DropBox是否在每次更改后都制作数据库的副本(或rdiff)?如果是这样,本地副本没有太多的开销。如果不是,那么只需在DropBox需要的地方拷贝本地拷贝。 – 2010-03-15 19:25:34