目录
1、github上获取源码,编译
地址:https://github.com/devbean/QtCipherSqlitePlugin
官方说明:https://github.com/devbean/QtCipherSqlitePlugin/wiki/How-to-use
压缩包:QtCipherSqlitePlugin-develop.zip
编译时,我的VS2015、Qt5.11.0,在sqlitecipher.cpp中,593行处异常;
成功后:
2、将生成的dll其拷贝到QT中对应目录中
注意:release和debug版不通用!
3、VS中创建Qt工程,引用SQL
验证是否可用:
qDebug() << QSqlDatabase::drivers();
4、补全动态库
创建_files.bat文件,运行。
D:\ProgramTools\Qt\5.11.0\msvc2015\bin\windeployqt.exe SqliteEncrypt.exe -qml
pause
注意:新项目可能不会遗漏sqldrivers中的sqlitecipher.dll,但对已有项目非常有可能忘记,我在这生生卡了大半天,qDebug输出的driver中就是没有SQLITECIPHER!!!对比工程配置啥都一样,Demo也没错,最后发现是这个问题,气死!另,推荐文件比较神器:Beyond Compare。
5、使用加密数据库
加密后的数据库操作与未加密的基本都一样,只是在打开的时候不同,把驱动QSQLITE换成SQLITECIPHER。
//db = QSqlDatabase::addDatabase("QSQLITE");
db = QSqlDatabase::addDatabase("SQLITECIPHER");
db.setDatabaseName(db_name);//数据库文件全路径
db.setPassword("123456");//密码
db.setConnectOptions("QSQLITE_USE_CIPHER=sqlcipher; SQLCIPHER_LEGACY=1; SQLCIPHER_LEGACY_PAGE_SIZE=4096");//连接配置
if (!db.open())
qDebug() << "Can not open connection: " << db.lastError();
数据库的加密方式有多种,我用的是:sqlcipher,其他还有aes128cbc、aes256cbc、chacha20。这段代码是从官方demo中摘出来的。
使用工具 SQLiteStudio打开数据库:
到这里常规使用就应该没问题了。
6、多数据库操作
我处理项目中的数据库较多,有的还需要attach,又踩了一些坑。
6.1 同时打开多数据库
bool SqliteEncrypt::OpenDB(QString db_name, QString alias)
{
if (!QSqlDatabase::contains(db_name))
{//打开数据库,注意带上数据库连接标识alias,用于同时打开多个数据库用,非数据库名
db = QSqlDatabase::addDatabase("SQLITECIPHER", alias);
db.setDatabaseName(db_name);//数据库文件全路径
db.setPassword("123456");//密码
db.setConnectOptions("QSQLITE_USE_CIPHER=sqlcipher; SQLCIPHER_LEGACY=1; SQLCIPHER_LEGACY_PAGE_SIZE=4096");//连接配置
if (!db.open()) {
qDebug() << "Can not open connection: " << db.lastError();
return false;
}
}
return true;
}
6.2 获取指定数据库
注意:用alias获取。
QSqlDatabase db = QSqlDatabase::database(db_alias);
6.3 附着数据库attach
这里有几个坑,在SQL编辑器里验证语句正确,但在代码中总是失败。
1、用旧数据库QSQLITE_CREATE_KEY创建密码后,attach总出错,错误是Error: QSqlError("26", "Unable to fetch row", "file is not a database");
2、attach语句加上KEY=密码,同样报Error: QSqlError("26", "Unable to fetch row", "file is not a database");
3、db_attach用相对路径,加上KEY=密码,返回值会为true,但实际没成功,在查询时报Error: QSqlError("1", "Unable to execute statement", "no such table: DB2.test")。
解决方法:
1、一定要重新创建带密码的新库!!然后再把旧库中的表复制进去就成功了。
2、Attach语句中不带KEY,表示用和主数据库相同的密码(或空密码)。
bool SqliteEncrypt::AttachDB(QString db_alias, QString db_attach, QString _alias)
{
bool res = false;
QString sql = "ATTACH DATABASE '" + db_attach + "' AS " + _alias;// +" KEY '123456'; ";
QSqlQuery query(db.database(db_alias));
res = query.prepare(sql);
if (!res) qDebug() << "Error:" << query.lastError();
res = query.exec();
if (!res) qDebug() << "Error:" << query.lastError();
return res;
}
因本人水平有限,深层原因未能明了,望知道原因的朋友留言告知。
6.4 操作表
从DB1里查询DB2
bool SqliteEncrypt::SelectDB(QString db_alias, QString sql)
{
sql = "Select * from DB2.test";
bool res = false;
db = QSqlDatabase::database(db_alias);
QSqlQuery query1(db);
res = query1.prepare(sql);
if (!res) qDebug() << "Error:" << query1.lastError();
res = query1.exec();
if (!res) qDebug() << "Error:" << query1.lastError();
int nCount = query1.record().count();//获取查询记录的字段数
return res;
}
6.5 查询结果
6.6 关闭数据库
数据库打开后,文件被占用,需关闭才能做剪切、删除等操作。
void SqliteEncrypt::CloseDB(QString db_alias)
{
if (QSqlDatabase::contains(db_alias)) {
db.database(db_alias);
db.close();
db.removeDatabase(db_alias);
}
}
7、总结
SQliteCipher没什么难点,把自己踩过的坑记录下来,能帮到大家就更好了。这一套操作整下来 真是把自己气坏了,基本功太不扎实,往后的路还很长,需不断学习,提升自己。与各位朋友共勉。
8、参考
SQLite Encryption Extension: Documentation
How to use · devbean/QtCipherSqlitePlugin Wiki · GitHub
编译出带加密功能的 SQLite Qt 插件并用SQLiteStudio进行查看_斧冰-CSDN博客
为Qt中的SQLite添加密码并加密 - BlueRose's Blog
使用SQLite附加(ATTACH)数据库时,需要注意数据文件编码的问题_weixin_33692284的博客-CSDN博客