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:\Program\Qt\Qt5.10.0\5.10.0\mingw53_32\include\QtCore\5.10.0\QtCore
D:\Program\Qt\Qt5.10.0\5.10.0\mingw53_32\include\QtSql\5.10.0\QtSql
然后在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:\Program\Qt\Qt5.10.0\5.10.0\Src\qtbase\src\plugins\sqldrivers\sqlite
找到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,
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
QT实现支持加密的Sqlite数据库引擎的更多相关文章
- 让PDF.NET支持最新的SQLite数据库
最近项目中用到了SQLite,之前项目中用的是PDF.NET+MySQL的组合,已经写了不少代码,如果能把写好的代码直接用在SQLite上就好了,PDF.NET支持大部分主流的数据库,这个当然可以,只 ...
- 在C#中,如何连接已加密的Sqlite数据库
对数据加密分两种,一种是对数据库本身进行加密,另一种是对数据表中的数据进行加密, 如果SQLite数据库加密,我这里使用的一个管理工具叫SQLiteDeveloper,如下就可以加密数据库 , 如果在 ...
- C#访问加密的SQLite数据库
前提:一个项目需要存储各种密码数据,使用的嵌入式的SQLite数据库.默认的SQLite数据库是没有加密的,这样相当不安全.找呀找呀找方法... 方法: 1.使用SQLite管理器加密. 部分SQLi ...
- PDF.NET支持最新的SQLite数据库
最近项目中用到了SQLite,之前项目中用的是PDF.NET+MySQL的组合,已经写了不少代码,如果能把写好的代码直接用在SQLite上就好了,PDF.NET支持大部分主流的数据库,这个当然可以,只 ...
- Sqlite数据库的加密
最近在做一个winform的程序,考虑用Sqlite的数据库,小巧而实用,比Access强多了,不过需要加密,不过free版本没有实现加密,有一些c++的实现:比如:http://www.sqlite ...
- c# sqlite 数据库加密
c# sqlite 数据库加密 2010-05-29 10:55 用了ADO.NET 2.0 SQLite Data Provider这样可以直接利用它来创建一个加密的sqlite数据库.有关c#代码 ...
- C#程序使用SQLite数据库
转至 http://www.cnblogs.com/redmoon/archive/2006/12/09/587617.html System.Data.SQLite(SQLite ADO.NET 2 ...
- 如何C#操作SQLite数据库
或许有人之前在java开发中使用过SQLite,对它有些印象.在用Winform或Wpf开发小应用程序时,发现用SQLite数据库也是不错的.就像一个会员管理软件,开发完毕后,可以省去想sqlserv ...
- android开发之路09(浅谈SQLite数据库01)
1.SQLite数据库: SQLite 是一个开源的嵌入式关系数据库,实现自包容.零配置.支持事务的SQL数据库引擎. 其特点是高度便携.使 用方便.结构紧凑.高效.可靠. 与其他数据库管理系统不同, ...
随机推荐
- spring的声明式事务和编程式事务
事务管理对于企业应用来说是至关重要的,当出现异常情况时,它可以保证数据的一致性. Spring事务管理的两种方式 1.编程式事务 使用Transaction Ttempleate或者直接使用底层的Pl ...
- clause
clause 英 [klɔːz] 美 [klɔz] 口语练习 跟读 n. 条款:[计] 子句 specify 英 ['spesɪfaɪ] 美 ['spɛsɪfaɪ] 口语练习 跟读 vt. 指 ...
- js访问对象属性的方式“.”与“[]”的区别
. 和 [] 没多大区别,作用完全相同.但是 一般情况下建议使用 . 写法,这样比较接近其它语言的面向对象写法,易读 如果属性名是动态的(比如变量中),只能使用 [] 写法.如 var person= ...
- RedisTemplate在项目中的应用
如下主要通去年无聊做的 "涂涂影院后台管理系统" 一个 demo,看 RedisTemplate 的使用. 体验地址:http://video.71xun.com:8080 账户 ...
- go语言的坑
go语言在for循环中遍历的临时变量地址是一样的 func main() { //SetLogConfToEtcd() for i := 0; i < 5; i++ { a := i fmt.P ...
- 如何调试 Windows 服务
概要 本文分步介绍了如何使用 WinDbg 调试程序 (windbg.exe) 调试 Windows 服务. 要调试 Windows 服务,可以在服务启动后将 WinDbg 调试程序附加到托管该服务的 ...
- 使用WinDbg调试入门(内核模式)
windbg是一个内核模式和用户模式调试器,包含在Windows调试工具中.这里我们提供了一些实践练习,可以帮助您开始使用windbg作为内核模式调试器. 设置内核模式调试 内核模式调试环境通常有两台 ...
- Xamarin.IOS/Mac开发中遇到的问题
虚拟机中安装的mac系统无法识别iphone 今天在 Xamarin.iOS 应用的免费预配 时,进行到 5.插入要在其中部署应用的 iOS 设备. 在第8选择iphone设备时,发现iphone并没 ...
- [RN] React Native 下实现底部标签(支持滑动切换)
上一篇文章 [RN] React Native 下实现底部标签(不支持滑动切换) 总结了不支持滑动切换的方法,此篇文章总结出 支持滑动 的方法 准备工作之类的,跟上文类似,大家可点击上文查看相关内容. ...
- 括号匹配(POJ2955)题解
原题地址:http://poj.org/problem?id=2955 题目大意:给出一串括号,求其中的最大匹配数. 我这么一说题目大意估计很多人就蒙了,其实我看到最开始的时候也是很蒙的.这里就来解释 ...