准备工作
1. 创建数据库文件
2. 打开数据库
3. 创建表格
4. 插入数据
5. 更新数据
6. 查询某行某列
7. 获取一列数据
8. 删除一行数据
9 关闭数据库
文章涉及到使用sqlite数据库保存整型,字符串,二进制以及时间类型的操作
在QT中调用Sqlite需在.pro文件中添加
本文使用停车系统中使用的数据库为例,我们先创建一个结构体把我们需要保存的数据整理一下,便于操作
1 2 3 4 5 6 7 8 9 10 11
| typedef struct SQL_DATA{ QString t_pl; /* 车牌号 */ QString t_location; /* 车位号 */ QString t_card; /* 卡号 */ int t_featuresize; /* 人脸特征数据大小 */ QByteArray t_featuredata; /* 人脸特征数据 */ QString t_datetime; /* 存车时间 */ //int t_way; /* 存车方式 */ } SQL_DATA_TypeDef;
Q_DECLARE_METATYPE(SQL_DATA)
|
在对数据库进行操作时,建议创建一个数据库类,本文中创建的类名为HSSql, 在头文件中添加数据库相关头文件
1 2 3
| #include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery>
|
下面简单介绍数据库的简单使用
1. 创建数据库文件函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| /* .h文件 */ QSqlDatabase create_db(QString fileName, QString identifier = "Topp");
/* .c文件 */ QSqlDatabase HSSql::create_db(QString fileName, QString identifier) { QSqlDatabase db; QString name = QCoreApplication::applicationDirPath() + "/" + fileName + ".db"; db = QSqlDatabase::addDatabase("QSQLITE", identifier); db.setDatabaseName(name);
QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForLocale(codec);
return db; }
|
2. 打开数据库
1 2 3 4 5 6
| bool open_db(QSqlDatabase db);
bool HSSql::open_db(QSqlDatabase db) { return db.open(); }
|
3. 创建表格
1 2 3 4 5 6 7 8 9 10
| bool create_table(QSqlDatabase db, QString sql_command);
bool HSSql::create_table(QSqlDatabase db, QString sql_command) { if(!open_db(db)){ return false; } QSqlQuery sqlquery(db); return sqlquery.exec(sql_command); }
|
4. 插入数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| bool insert_data_into_table(QSqlDatabase db, QString table, SQL_DATA_TypeDef* data_t);
bool HSSql::insert_data_into_table(QSqlDatabase db, QString table, SQL_DATA_TypeDef *data_t) { m_command = "create table userInfo( pl char(20) not null, \ location char(9) not null, \ card char(9), \ featuresize int, \ featuredata blob, \ datetime char(20))"; QSqlQuery sqlquery(db); /* 此处可根据实际应用判断数据的唯一性 */ QString command = QString("INSERT INTO %1 (pl,location,card,featuresize,featuredata,datetime) VALUES (:pl,:location,:card,:featuresize,:featuredata,:datetime);").arg(table); sqlquery.prepare(command); sqlquery.bindValue(":pl", data_t->t_pl); sqlquery.bindValue(":location", data_t->t_location); sqlquery.bindValue(":card", data_t->t_card); sqlquery.bindValue(":featuresize", data_t->t_featuresize); sqlquery.bindValue(":featuredata", data_t->t_featuredata); sqlquery.bindValue(":datetime", data_t->t_datetime);
if(sqlquery.exec()) return true; else { qDebug() << sqlquery.lastError().text(); return false; } }
|
5. 更新数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| bool update_userInfo(QSqlDatabase db, QString table, int id, QString col_name, QString new_value);
bool HSSql::update_userInfo(QSqlDatabase db, QString table, int id, QString col_name, QString new_value) { QSqlQuery sqlquery(db); QString command = QString("update %1 set %2 = %3 where id = :id;").arg(table) .arg(col_name) .arg(new_value); sqlquery.bindValue(":id", id); if(!sqlquery.exec()) { return false; } else { return true; } }
|
6. 查询某行某列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| bool getLocationByPl(const QSqlDatabase &db, const QString &table, const QString &pl, QString &location);
bool HSSql::getLocationByPl(const QSqlDatabase &db, const QString &table, const QString &pl, QString &location) { QSqlQuery sqlquery(db); QString command = QString("select location from %1 where pl = '%2';").arg(table).arg(pl); if(!sqlquery.exec(command)) { qDebug() << sqlquery.lastError().text(); return false; }
while (sqlquery.next()) { location = sqlquery.value(0).toString(); // qDebug() << location; /* 查寻过程中有时会查询到空字符串,所以我在下面加了条件判断 */ if(!location.isEmpty()) { return true; } }
return true; }
|
7. 获取一列数据
1 2 3 4 5 6
| bool getOneColumn(const QSqlDatabase &db, const QString &table, const QString &str, void(*callBack)(QStringList, void *),void *pUserData); bool getOneColumn(const QSqlDatabase &db, const QString &table, const QString &str, void(*callBack)(QList<int> &, void *),void *pUserData); bool getOneColumn(const QSqlDatabase &db, const QString &table, const QString &str, void(*callBack)(QList<QByteArray> &, void *),void *pUserData);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| bool HSSql::getOneColumn(const QSqlDatabase &db, const QString &table, const QString &str, void (*callBack)(QStringList, void *), void *pUserData) { QSqlQuery sqlquery(db); QStringList str_list; QString command = QString("select %1 from %2;").arg(str).arg(table); if(!sqlquery.exec(command)) return false; while (sqlquery.next()) { str_list << sqlquery.value(0).toString(); } callBack(str_list, pUserData); return true; }
bool HSSql::getOneColumn(const QSqlDatabase &db, const QString &table, const QString &str, void (*callBack)(QList<int> &, void *), void *pUserData) { QSqlQuery sqlquery(db); QList<int> int_list; QString command = QString("select %1 from %2;").arg(str).arg(table); if(!sqlquery.exec(command)) return false; while (sqlquery.next()) { int_list << sqlquery.value(0).toInt(); } callBack(int_list, pUserData); return true; }
bool HSSql::getOneColumn(const QSqlDatabase &db, const QString &table, const QString &str, void (*callBack)(QList<QByteArray> &, void *), void *pUserData) { QSqlQuery sqlquery(db); QList<QByteArray> array_list; QString command = QString("select %1 from %2;").arg(str).arg(table); if(!sqlquery.exec(command)) return false; while (sqlquery.next()) { array_list << sqlquery.value(0).toByteArray(); } callBack(array_list, pUserData); return true; }
|
8. 删除一行数据
1 2 3 4 5 6 7 8 9
| bool delete_data(QSqlDatabase db, QString table, int key);
bool HSSql::delete_data(QSqlDatabase db, QString table, int key) { QSqlQuery sqlquery(db); QString delete_sql = QString("delete from %1 where pl = %2").arg(table).arg(key); if(sqlquery.exec(delete_sql)) return true; else return false; }
|
9 关闭数据库
1
| void close_db(QSqlDatabase &db) { if(open_db(db)) db.close(); }
|
另外,在构造函数中需要对用户创建了结构体进行注册
1
| qRegisterMetaType<SQL_DATA>("SQL_DATA");
|
在创建表格时,需要一条数据库命令,这个命令要和我们创建的结构体对应起来,其中
char -– QString
int -– int
图片,数据等其他二进制文件 -– blob
datetime -– char (sqlite不支持datetime类型,所以这里使用char型代替,保存为字符串格式)
1 2 3 4 5 6
| m_command = "create table userInfo( pl char(9) not null, \ location char(9) not null, \ card char(9), \ featuresize int, \ featuredata blob, \ datetime char(20))";
|
下面写一个demo仅供参考,未测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| m_command = "create table userInfo( pl char(9) not null, \ location char(9) not null, \ card char(9), \ featuresize int, \ featuredata blob, \ datetime char(20))";
m_sql = new HSSql; QSqlDatabase db = m_sql->create_db("ToppDb"); m_sql->create_table(db, m_command);
SQL_DATA_TypeDef data_t; data_t.t_pl = "ABC"; data_t.t_card = "961202"; data_t.t_location = "201"; data_t.t_featuresize = 123456; data_t.t_datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
QByteArray array; array.resize(2); array[0] = 0xaa; array[1] = 0x03; data_t.t_featuredata = array;
m_sql->insert_data_into_table(db, "userInfo", &data_t);
m_sql->close_db(db);
|
以下是调试过程中遇到的问题:
1. 查询的到的数据(有汉字)在UI上显示乱码
原因: 是由于保存的字符串中的汉字编码为GBK
解决:将字符串先转成UTF-8编码再保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| QString UTF8ToGBK(const QString &utfStr);
QString ToppHMI::UTF8ToGBK(const QString &utfStr) { QString ustr = QTextCodec::codecForName("UTF-8")->toUnicode(utfStr.toLocal8Bit().data()); QByteArray gbk_byte = QTextCodec::codecForName("GBK")->fromUnicode(ustr);
return QString(gbk_byte); }
QString gbkToUtf8(const QString &gbkStr);
QString CameraUI::gbkToUtf8(const QString &gbkStr) { QString ustr = QTextCodec::codecForName("GBK")->toUnicode(gbkStr.toLocal8Bit().data()); QByteArray utf8_byte = QTextCodec::codecForName("UTF-8")->fromUnicode(ustr);
return QString(utf8_byte); }
|
2. 获取当前时间与数据保存时间之间的差值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| /* 将查询到的时间字符串转成时间戳 */ QDateTime dt = QDateTime::fromString(start.at(i), "yyyy/MM/dd HH:mm:ss"); uint start_T = dt.toTime_t();
/* 获取当前时间时间戳 */ QDateTime eDT = QDateTime::currentDateTime(); uint et = eDT.toTime_t(); /* 取其差值 */ uint dif = et - sDT;
ushort day = dif / 86400; unsigned char hour = ( dif % 86400 ) / 3600; unsigned char minute = (( dif % 86400 ) % 3600) / 60; unsigned char second = (( dif % 86400 ) % 3600) % 60;
return QString("%1天%2时%3分%4秒").arg(day,3,10,QLatin1Char('0')) .arg(hour,2,10,QLatin1Char('0')) .arg(minute,2,10,QLatin1Char('0')) .arg(second,2,10,QLatin1Char('0'));
|
3. 提供一个保存图片的思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 1. 使用opencv读取图片得到图片的Mat型值 2. 使用数据库保存Mat的type, cols, rows, elemSize, ptr
e.g sdt.t_imgtype = ret_image.type(); sdt.t_imgcols = ret_image.cols; sdt.t_imgrows = ret_image.rows; sdt.t_imgsize = ret_image.elemSize(); const size_t data_size = ret_image.cols * ret_image.rows * ret_image.elemSize(); QByteArray imgByte = QByteArray::fromRawData( (const char*)ret_image.ptr(), data_size ); sdt.t_imgdata = imgByte;
3. 加载数据库中的图片 cv::Mat img = cv::Mat(sdt.t_imgrows,sdt.t_imgcols, sdt.t_imgtype, (void*)sdt.t_imgdata.data()).clone(); QImage image((const uchar*)img.data, img.cols, img.rows, QImage::Format_RGB888);
|
4. 使用sqlite3工具可以很方便的进行调试
下载 sqlite3二进制文件
64位电脑下载以下两个文件
解压之后如图
在地址栏输入cmd(也可以将sqlite3加入环境变量)打开调试窗口,输入
sqlite3 [数据库文件的绝对地址]
出现版本号即打开成功
输入 .table 查看数据库中的表格,这里只有一张表userInfo
更多相关数据库操作可以看 21分钟 MySQL 入门教程