QT实现支持加密的Sqlite数据库引擎
Sqlite数据库使用很广泛,我们经常会在发布一些小型软件的时候使用它,因为它不需要安装服务器。QT默认的数据库引擎是支持SQLITE数据库的,但并不支持对数据库加密,不加密的Sqlite数据库任何人都可以很轻易的打开它,这让我们的数据很不安全,很容易泄露或被篡改。自己对数据库进行加密当然也可以,但是那就不是通用的了,其他人用其他数据库工具也无法打开数据库文件,要想采用通用的加密方式,我们可以在网上找到sqlite3.dll这个动态库,这个动态库能够支持对Sqlite数据库文件加密。所以如果你想使用加密版的Sqlite,第一种方式就是直接使用sqlite3.dll里面的函数,这种方式简单,但是你就无法使用QT自带的数据库引擎了,这有很多缺点,用过QSqlDatabase的人应该知道,这个类可以打开很多种数据库类型,比如mysql,sqlserver,sqlite等,而且操作函数都是一致的,这使得我们在更换不同数据库时很方便,不需要做太大的改动,另外如果你不用QT默认的数据库引擎,那么就无法使用如QSqlQueryModel进行数据的展示了。 那么有什么更好的方法吗?当然有,实际上QT给我们提供了一种方法,就是创建新的数据库引擎。而且要实现Sqlite非常简单,几乎可以用QT自带的文件做很小的修改就实现。下面我们来讲一下具体的操作。 1.创建工程 打开QtCreator,新建项目,选择Library,C++库。 类型选择:Qt plugin,项目名称SQLITEEX 类名:QSQLiteExDriverPlugin,基类选择:QSqlDriverPlugin,然后点击下一步完成创建。 ? 2. 找到你安装QT的目录,将下面两个目录复制到工程目录下: D:ProgramQtQt5.10.05.10.0mingw53_32includeQtCore5.10.0QtCore D:ProgramQtQt5.10.05.10.0mingw53_32includeQtSql5.10.0QtSql 然后在SQLITEEX.pro工程文件添加: INCLUDEPATH +=$$PWD/QtCore INCLUDEPATH +=$$PWD/QtSql ? 3. 下载sqlite3.dll,将sqlite3.lib和sliqte3.h文件放到工程目录下。将sqlite3.h添加到工程。 然后在SQLITEEX.pro工程文件添加: LIBS += -L$$PWD -lsqlite3 ? 4. 新建文件qsql_sqliteex_p.h,qsql_sqliteex.cpp。然后在QT源码下找到sqlite的实现源码,例如QT5.10在以下目录: D:ProgramQtQt5.10.05.10.0Srcqtbasesrcpluginssqldriverssqlite 找到qsql_sqlite_p.h文件,将#define QSQL_SQLITE_H到#endif中间的内容复制到qsql_sqliteex_p.h, 找到qsql_sqlite.cpp文件,将所有内容复制到qsql_sqliteex.cpp。然后将这两个文件中的类名做下修改: QSQLiteDriverPrivate修改为:QSQLiteExDriverPrivate QSQLiteDriver修改为:QSQLiteExDriver QSQLiteResultPrivate修改为:QSQLiteExResultPrivate QSQLiteResult修改为:QSQLiteExResult ? 5.修改QSQLiteExDriver::open 找到QSQLiteExDriver::open函数,修改为内容: bool QSQLiteExDriver::open(const QString & db,const QString & user,const QString & password,const QString & host,int port,const QString & conOpts) { Q_D(QSQLiteExDriver); if (isOpen()) close(); int timeOut = 5000; bool sharedCache = false; bool openReadOnlyOption = false; bool openUriOption = false; #ifndef QT_NO_REGULAREXPRESSION static const QLatin1String regexpConnectOption = QLatin1String("QSQLITE3_ENABLE_REGEXP"); bool defineRegexp = false; int regexpCacheSize = 25; #endif const auto opts = conOpts.splitRef(QLatin1Char(‘;‘)); for (auto option : opts) { option = option.trimmed(); if (option.startsWith(QLatin1String("QSQLITE3_BUSY_TIMEOUT"))) { option = option.mid(20).trimmed(); if (option.startsWith(QLatin1Char(‘=‘))) { bool ok; const int nt = option.mid(1).trimmed().toInt(&ok); if (ok) timeOut = nt; } } else if (option == QLatin1String("QSQLITE3_OPEN_READONLY")) { openReadOnlyOption = true; } else if (option == QLatin1String("QSQLITE3_OPEN_URI")) { openUriOption = true; } else if (option == QLatin1String("QSQLITE3_ENABLE_SHARED_CACHE")) { sharedCache = true; } #ifndef QT_NO_REGULAREXPRESSION else if (option.startsWith(regexpConnectOption)) { option = option.mid(regexpConnectOption.size()).trimmed(); if (option.isEmpty()) { defineRegexp = true; } else if (option.startsWith(QLatin1Char(‘=‘))) { bool ok = false; const int cacheSize = option.mid(1).trimmed().toInt(&ok); if (ok) { defineRegexp = true; if (cacheSize > 0) regexpCacheSize = cacheSize; } } } #endif } int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)); openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE); if (openUriOption) openMode |= SQLITE_OPEN_URI; openMode |= SQLITE_OPEN_NOMUTEX; if (sqlite3_open_v2(db.toUtf8().constData(),&d->access,openMode,NULL) == SQLITE_OK) { if(sqlite3_key(d->access,password.toUtf8(),password.toUtf8().length()) != SQLITE_OK) { if (d->access) { sqlite3_close(d->access); d->access = 0; } setLastError(qMakeError(d->access,tr("Error opening database by key"),QSqlError::ConnectionError)); setOpenError(true); return false; } sqlite3_busy_timeout(d->access,timeOut); setOpen(true); setOpenError(false); #ifndef QT_NO_REGULAREXPRESSION if (defineRegexp) { auto cache = new QCache<QString,QRegularExpression>(regexpCacheSize); sqlite3_create_function_v2(d->access,"regexp",2,SQLITE_UTF8,cache,&_q_regexp,NULL,&_q_regexp_cleanup); } #endif return true; } else { if (d->access) { sqlite3_close(d->access); d->access = 0; } setLastError(qMakeError(d->access,tr("Error opening database"),QSqlError::ConnectionError)); setOpenError(true); return false; } } ?6.QSQLiteExDriverPlugin添加create函数 在QSQLiteExDriverPlugin类头文件添加公有函数: QSqlDriver* create(const QString &) Q_DECL_OVERRIDE; ?然后实现这个函数: QSqlDriver *QSQLiteExDriverPlugin::create(const QString &name) { if (name == QLatin1String("QSQLITEEX")) { QSQLiteExDriver* driver = new QSQLiteExDriver(); return driver; } return 0; } ? 7.修改SQLITEEX.json文件 修改为: { "Keys" : [ "QSQLITEEX" ] } ? 8.修改.pro文件 Debug:TARGET = SQLITEEXD Release:TARGET = SQLITEEX TEMPLATE = lib CONFIG += plugin DESTDIR = ./plugin/sqldrivers ? 9.到此修改完成,编译工程分别生成debug版的dll和release版的dll,注意发布的时候sqlite3.dll文件要放到exe目录下。 10.创建测试工程 (1)创建一个控制台程序, (2)添加代码 #include <QCoreApplication> #include <QtSql/QtSql> #include <QPluginLoader> #include <iostream> using namespace std; int main(int argc,char *argv[]) { QCoreApplication a(argc,argv); #ifdef QT_NO_DEBUG QPluginLoader driverload(qApp->applicationDirPath()+"/plugin/sqldrivers/SQLITEEX.dll"); #else QPluginLoader driverload(qApp->applicationDirPath()+"/plugin/sqldrivers/SQLITEEXD.dll"); #endif if(driverload.load()) { QSqlDriverPlugin *plugin=qobject_cast<QSqlDriverPlugin*>(driverload.instance()); if(plugin) { QSqlDriver *driver=plugin->create("QSQLITEEX"); QSqlDatabase db; db=QSqlDatabase::addDatabase(driver); db.setDatabaseName("mydatabase.db"); db.setPassword("123456"); if(db.open()) { QSqlQuery qry(db); qry.exec("create table t_trade(order_id varchar(100))"); qry.exec("insert into t_trade(order_id) values(‘10001‘)"); qry.exec("insert into t_trade(order_id) values(‘10002‘)"); qry.exec("select * from t_trade"); while(qry.next()) { cout<<qry.value(0).toString().toStdString()<<endl; } } } else cout<<"get plugin fail"<<endl; } else cout<<"driver load fail"<<endl; return a.exec(); } ?(3)将plugin目录放到生成的exe目录下: ? (4)运行结果 ? 完整工程下载:https://download.csdn.net/download/jonahking2012/10688526 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |