zoukankan      html  css  js  c++  java
  • 一种通用的Qt数据库接口操作方法

    一种通用的Qt数据库接口操作方法

    自己开发了一个股票软件,功能很强大,需要的点击下面的链接获取:

    https://www.cnblogs.com/bclshuai/p/11380657.html

    目录

    1       前言... 1

    2       QT环境下数据库配置... 2

    2.1      开发环境... 2

    2.2      配置工作... 2

    2.3      数据库驱动配置... 2

    2.4      创建数据库增加数据库表格... 3

    2.5      包含头文件和库文件... 3

    2.6      初始化数据库... 4

    2.7      打开数据库... 5

    3       数据库增删改查操作... 5

    3.1      常规增删改查操作... 5

    3.1.1     插入数据... 5

    3.1.2     更新数据... 6

    3.1.3     查询数据... 7

    3.1.4     删除数据... 10

    3.2      基于模板的数据库操作... 11

    3.2.1     增删改查接口说明... 11

    3.2.2     增删改查接口实现... 13

    3.3      对比总结... 19

    1         前言

    通常对数据库的操作都是根据具体的表格和具体的条件编辑SQL语句,然后调用SQL语句去操作数据库。对于固定的条件编写SQL语句很方便,但是对于数据查询,通常根据用户动态输入的条件去组织SQL,这就要制定一定的策略规则去组织SQL语句,实现一个通用的数据查询接口,只要将条件按照一定的格式输入,就可以实现自动化的SQL语句编写。本文主要讲解QT环境下如何使用数据库,介绍了常用的数据库增删改查操作方法。然后又介绍了一种通用的参数模板方法,定义一些规范和参数模板,使用者只需要按照要求输入参数条件,就可以实现对不同表格的相同的操作。

    2         QT环境下数据库配置

    2.1   开发环境

    Qt5.9.6 vs2015,使用QSQLITE保存数据到本地数据库文件。实现增删改查的功能。

    2.2   配置工作

    2.3   数据库驱动配置

    将Qt安装目录下D:\QT\Qt5.9.6\5.9.6\msvc2015_64\plugins\的数据库驱动文件夹sqldrivers复制到你的开发程序exe路径下,如下图所示。

     

    2.4   创建数据库增加数据库表格

    使用Sqlite工具DB Browser for SQLite.exe创建数据库,并新建数据库的表格。

     

    2.5   包含头文件和库文件

     

     

    2.6   初始化数据库

    db_ = QSqlDatabase::addDatabase("QSQLITE");

        QString dbpath = QCoreApplication::applicationDirPath() + "/localSqliteDb";

        db_.setDatabaseName(dbpath);

    2.7   打开数据库

    if (!db_.open())

            {

                msg = tr("open local database fail");

                break;

            }

    3         数据库增删改查操作

    3.1   常规增删改查操作

    通常情况下我们操作数据库时,会根据数据库的字段名称,数据库表格名称,数据库字段值,筛选条件去组织SQL语句,如下所示的四种数据库常规操作,动态的组织SQL语句,组织条件,需要做很多的条件判断和筛选才能组织,非常麻烦。

    3.1.1            插入数据

    Query是数据库请求,可以执行SQL语句,可以将数据组织成一个字符串,符合SQL的语法,就可以插入数据,也可以通过bindValue函数来绑定数值与SQL模板中的别名,例如绑定task中的数值name和SQL模板中的标签:name,执行SQL语句时,就会用task中的数值name替换:name,通过exec函数来执行SQL语句。

    int LocalDb::onSaveTask(QVariantMap & task,QString& strMsg)

    {

        int errorCode = -1;

        do

        {

            QSqlQuery query;

            query.prepare("INSERT INTO alarmTask (id, name,type,target,similarity,time,createtime) "

                "VALUES ( :id,:name,:type,:target,:similarity,:time,:createtime)");

            query.bindValue(":id", QUuid::createUuid());

            query.bindValue(":name", task.value("name"));

            query.bindValue(":type", task.value("type"));

            query.bindValue(":target", task.value("target"));

            query.bindValue(":time", task.value("time"));

            query.bindValue(":similarity", task.value("similarity"));

            query.bindValue(":createtime", task.value("createtime"));

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                errorCode = error.type();

                strMsg = error.text();

                LOG_ERROR("insert task failed %s", strMsg.toStdString().c_str());

                break;

            }

            errorCode = 0;

            //创建图片解析任务

        } while (0);

        return errorCode;

    }

    3.1.2            更新数据

    更新数据采用update语句。同样采用QSqlQuery方法

    int LocalDb::onUpdateTask(QVariantMap & task, QString & strMsg)

    {

        int errorCode = -1;

        do

        {

            QSqlQuery query;

            query.prepare("update alarmTask set name=:name,type=:type,target=:target,similarity=:similarity,time=:time,createtime=:createtime where id=:id");

            query.bindValue(":id", task.value("id"));

            query.bindValue(":name", task.value("name"));

            query.bindValue(":type", task.value("type"));

            query.bindValue(":target", task.value("target"));

            query.bindValue(":time", task.value("time"));

            query.bindValue(":similarity", task.value("similarity"));

            query.bindValue(":createtime", task.value("createtime"));

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                strMsg = error.text();

                errorCode = error.type();

                LOG_ERROR("UpdateTask  failed %s", strMsg.toStdString().c_str());

                break;

            }

            errorCode = 0;

            //创建图片解析任务

        } while (0);

        return errorCode;

    }

    3.1.3            查询数据

    在使用查询时,如果是多个条件,例如select * from vehicle where vehicletype in (: vehiclecolor),如果使用query.bindValue(":vehiclecolor ", task.value("vehiclecolor "));当vehiclecolor值为多个时,例如‘红’,‘黄’。如果用query.bindValue(":vehiclecolor", task.value("vehiclecolor"));绑定值,会发现执行语句时无效。只有用将颜色组织成字符串后才有效,strCondition += QString(" vehiclecolor in (%1)  AND").arg(strtemp);

    void LocalDb::SlotQueryVehicleByCondition(int pageno, int pagesize, QMap<QString, QMap<QString, QString>> cond)

    {

        int errorCode = 0;

        QString msg;

        QString sqlcount = "SELECT count(*) from vehicle ";

        QVariantMap bindvalue;

        QString sqlserchpage = "SELECT * from vehicle ";//ORDER BY time DESC LIMIT :limit OFFSET :offset";

        QString strCondition = "";

        QString strtemp = "";

        if (cond.size() > 0)

        {

            strCondition = "where";

            //车辆类型

            if (cond.contains("vehicletype"))

            {

                strtemp = GetStringCondition(cond["vehicletype"].keys());

                strCondition += QString(" vehicletype in (%1)  AND").arg(strtemp);

            }

            //车牌号码

            if (cond.contains("vehiclenum"))

            {

                strtemp = cond["vehiclenum"]["vehiclenum"];

                strCondition += QString(" vehiclenum in ('%1')  AND").arg(strtemp);

            }

            //特征标识

            if (cond.contains("mark"))

            {

                if (cond["mark"].contains("副驾驶"))

                {

                    strCondition += QString(" visepilot in ('是') AND");

                }

                if (cond["mark"].contains("挂件"))

                {

                    strCondition += QString(" hangthing in ('是') AND");

                }

                if (cond["mark"].contains("遮阳板"))

                {

                    strCondition += QString(" hidesunplate in ('是') AND");

                }

                if (cond["mark"].contains("危险品"))

                {

                    strCondition += QString(" danger in ('是') AND");

                }

            }

            //车牌颜色

            if (cond.contains("platecolor"))

            {

                strtemp = GetStringCondition(cond["platecolor"].keys());

                strCondition += QString(" platecolor in (%1)  AND").arg(strtemp);

            }

            //车身颜色

            if (cond.contains("vehiclecolor"))

            {

                strtemp = GetStringCondition(cond["vehiclecolor"].keys());

                strCondition += QString(" vehiclecolor in (%1)  AND").arg(strtemp);

            }

            if (cond.contains("time"))

            {

                if (cond["time"].contains("starttime"))

                {

                    strCondition += QString(" time >='%1' AND").arg(cond["time"]["starttime"]);

     

                }

                if (cond["time"].contains("endtime"))

                {

                    strCondition += QString(" time <='%1' AND").arg(cond["time"]["endtime"]);

                }

            }

            if (strCondition.right(4) == " AND")//去除最后的 AND

            {

                strCondition = strCondition.left(strCondition.length() - 4);

            }

            if (strCondition == "where")//无条件

            {

                strCondition = "";

            }

        }

        QVariantMap replyData;

        do

        {

            //先查出符合条件的总数量

            QSqlQuery countquery;

            //先删除数据库中的数据

            sqlcount += strCondition;

            countquery.prepare(sqlcount);

            if (!countquery.exec()

                || !countquery.next())

            {

                QSqlError error = countquery.lastError();

                errorCode = error.type();

                msg = error.text();

                LOG_ERROR("query vehicle count failed,msg:%s", msg.toStdString().c_str());

                break;

            }

            quint64 totalCount = countquery.record().value(0).toULongLong();

            if (0 >= totalCount)

            {

                break;

            }

            QVariantList dataList;

            QSqlQuery query;

            sqlserchpage += strCondition;

            sqlserchpage += QString(" ORDER BY time DESC LIMIT %1 OFFSET %2").arg(pagesize).arg((pageno)* pagesize);

            query.prepare(sqlserchpage);

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                errorCode = error.type();

                msg = error.text();

                break;

            }

     

            while (query.next())

            {

                QSqlRecord record = query.record();

                int column = record.count();

                QVariantList recorditem;

                for (int i = 0; i < column; i++)

                {

                    QVariantMap data;

                    data.insert("N", record.fieldName(i));

                    data.insert("V", record.value(i));

                    recorditem.append(data);

                }

                QVariantMap item;

                item.insert("data", recorditem);

                dataList.append(item);

            }

            replyData.insert("totalCount", totalCount);

            replyData.insert("data", dataList);

     

        } while (0);

        singalQueryVehicle(errorCode, msg, replyData);

    }

    3.1.4            删除数据

    删除数据用delete,如果清空表格,则不带where条件。同样如果是一次删除多条记录,不能用bindValue去绑定值,计时绑定的值是拼接好的字符串,并且加上了引号都没用,需直接组织一个字符串。将多个taskId的值添加到字符串中。

    int LocalDb::deleteAlarmTask(QString id,QString& strMsg)

    {

        if (id=="")

        {

            return -1;

        }

        int errorCode = 0;

        QString msg;

        do

        {

     

            QSqlQuery query;

            //先删除数据库中的数据

            query.prepare("delete from alarmTask where id =:taskId");

            query.bindValue(":taskId",id);

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                errorCode = error.type();

                msg = error.text();

                LOG_ERROR("delete %s failed,msg:%s", id.toStdString().c_str(), msg.toStdString().c_str());

                return -1;

            }

           

        } while (0);

        return 0;

    }

    3.2   基于模板的数据库操作

    数据库的增删改查之间有很多相似之处,按照上面的方法去操作数据库,针对不同的表格的增删改查,都要自定义一个函数去操作具体的数据表格,并组织具体的sql语句,扩展性和通用性比较差,现在试图用四个函数实现所有表格的增删改查,需要定义一些规范和参数模板,使用者只需要按照要求输入参数条件,就可以实现对不同表格的相同的操作。

    3.2.1            增删改查接口说明

    /*新增记录

        QString table, 表格名称,

        QVariantMap& info, 插入表格的数据,名称值键值对

        QString& strMsg,返回错误消息

        */

        int insertTableRecord(QString table, QVariantMap& info, QString& strMsg);

        /*

        //cond

       

        /*删除记录

        QString table, 表格名称,

        QVariantList& cond, 判断条件,QVariantMap保存的键值对

        {

        "name":"target",

        "relation":"=", 关系运算符

        "value":"C://picture/1.jpg",

        "logical":"AND" 逻辑运算符,第一个没有逻辑运算符

     

        }  

        QString& strMsg,返回错误消息

        */

        int deleteTableRecord(QString table, QVariantList& cond, QString& strMsg);

        /*修改数据记录

        QString table, 表格名称,

        QVariantMap info 跟新数据的键值对

        QVariantList& cond, 判断条件,QVariantMap保存的键值对

        {

        "name":"target",

        "relation":"=", 关系运算符

        "value":"C://picture/1.jpg",

        "logical":"AND" 逻辑运算符,第一个没有逻辑运算符

     

        }

        QString& strMsg,返回错误消息

        */

        int updateTableRecord(QString table, QVariantMap info, QVariantList& cond, QString& strMsg);

        /*查询数据记录

        QString table, 表格名称,

        QVariantList& cond, 判断条件,QVariantMap保存的键值对

        {

        "name":"target",

        "relation":"=", 关系运算符

        "value":"C://picture/1.jpg",

        "logical":"AND" 逻辑运算符,第一个没有逻辑运算符

     

        }

        int pageno, 分页查询的页码,0开始

        int pagesize,分页查询每页数量

        QString strOrderKey,用于排序的键名称

        QString strOrder,正序还是逆序排列,逆序:DESC或者正序:ASC

        QString& strMsg,返回错误消息

        */

        int queryTableRecordByPage(QString table, QVariantList& cond, int pageno, int pagesize,QString strOrderKey,QString strOrder, QString& strMsg, QVariantMap& replyData);

    3.2.2            增删改查接口实现

    具体实现代码如下:

    int LocalDb::deleteTableRecord(QString table, QVariantList& cond, QString& strMsg)

    {

        //cond

        /*

        {

            "name":"target",

            "relation":"==", 关系运算符

            "value":"C://picture/1.jpg",

            "logical":"AND" 逻辑运算符,第一个没有逻辑运算符

     

        }*/

     

        if (table == "")

        {

            strMsg = "表格为空";

            return -1;

        }

        do

        {

            QString strQuery = "delete from "+ table;

            if (cond.size()!=0)

            {

                strQuery += " ";

                strQuery += "where ";

                for (int i = 0; i < cond.size();i++)

                {

                    if (cond[i].toMap().contains("logical"))

                    {

                        strQuery += cond[i].toMap().value("logical").toString();

                        strQuery += " ";

                    }

                    if (cond[i].toMap().contains("name"))

                    {

                        strQuery += cond[i].toMap().value("name").toString();

                        strQuery += " ";

                    }

                    if (cond[i].toMap().contains("relation"))

                    {

                        strQuery += cond[i].toMap().value("relation").toString();

                        strQuery += " ";

                    }

                    if (cond[i].toMap().contains("value"))

                    {

                        strQuery += cond[i].toMap().value("value").toString();

                        strQuery += " ";

                    }

                }

     

            }

           

            QSqlQuery query;

            //先删除数据库中的数据

            query.prepare(strQuery);

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                strMsg = error.text();

                LOG_ERROR("delete table:%s failed,msg:%s", table.toStdString().c_str(), strMsg.toStdString().c_str());

                return -1;

            }

     

        } while (0);

        return 0;

    }

     

    int LocalDb::updateTableRecord(QString table, QVariantMap info, QVariantList & cond, QString & strMsg)

    {

        int errorCode = -1;

        do

        {

            QSqlQuery query;

            QString strQuery = "update " + table + " set ";

            QVariantMap::iterator it;

            for (it = info.begin();it!= info.end();it++)

            {

                strQuery += it.key();

                strQuery += "=";

                strQuery += it.value().toString();

     

            }

            if (cond.size() != 0)

            {

                strQuery += " ";

                strQuery += "where ";

                for (int i = 0; i < cond.size(); i++)

                {

                    if (cond[i].toMap().contains("logical"))

                    {

                        strQuery += cond[i].toMap().value("logical").toString();

                        strQuery += " ";

                    }

                    if (cond[i].toMap().contains("name"))

                    {

                        strQuery += cond[i].toMap().value("name").toString();

                        strQuery += " ";

                    }

                    if (cond[i].toMap().contains("relation"))

                    {

                        strQuery += cond[i].toMap().value("relation").toString();

                        strQuery += " ";

                    }

                    if (cond[i].toMap().contains("value"))

                    {

                        strQuery += cond[i].toMap().value("value").toString();

                        strQuery += " ";

                    }

                }

     

            }

            query.prepare(strQuery);

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                strMsg = error.text();

                errorCode = error.type();

                LOG_ERROR("Update table %s failed %s", table.toStdString().c_str(), strMsg.toStdString().c_str());

                break;

            }

            errorCode = 0;

            //创建图片解析任务

        } while (0);

        return errorCode;

    }

     

    int LocalDb::insertTableRecord(QString table, QVariantMap& info,QString& strMsg)

    {

        int errorCode = 0;

        QString msg;

        QVariantMap data;

        if (info.size() == 0)

        {

            return -1;

        }

        QString strName = "";

        QString strValue = "";

        for (QVariantMap::iterator it = info.begin(); it != info.end(); it++)

        {

            strName += it.key();

            strName += ",";

            strValue += it.value().toString();

            strValue += ",";

        }

        //去除末尾的逗号

        strName = strName.left(strName.length() - 1);

        strValue = strValue.left(strValue.length() - 1);

        QString strSql = "INSERT INTO "+ table+" (" + strName + ") VALUES(" + strValue + ")";

        do

        {

            QSqlQuery query;

            query.prepare(strSql);

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                errorCode = error.type();

                strMsg = error.text();

                break;

            }

            errorCode = 0;

        } while (0);

        return errorCode;

    }

     

    int LocalDb::queryTableRecordByPage(QString table, QVariantList & cond, int pageno, int pagesize, QString strOrderKey, QString strOrder, QString & strMsg, QVariantMap& replyData)

    {

        if (table=="")

        {

            return -1;

        }

        int errorCode = -1;

        QString msg;

        QString sqlcount = "SELECT count(*) from "+ table;

        QString strQuery = "SELECT * from "+ table;//ORDER BY time DESC LIMIT :limit OFFSET :offset";

        if (cond.size() > 0)

        {

            QString strCondition = " where ";

            for (int i = 0; i < cond.size(); i++)

            {

                if (cond[i].toMap().contains("logical"))

                {

                    strCondition += cond[i].toMap().value("logical").toString();

                    strCondition += " ";

                }

                if (cond[i].toMap().contains("name"))

                {

                    strCondition += cond[i].toMap().value("name").toString();

                    strCondition += " ";

                }

                if (cond[i].toMap().contains("relation"))

                {

                    strCondition += cond[i].toMap().value("relation").toString();

                    strCondition += " ";

                }

                if (cond[i].toMap().contains("value"))

                {

                    strCondition += cond[i].toMap().value("value").toString();

                    strCondition += " ";

                }

            }

            sqlcount += strCondition;

            strQuery += strCondition;

        }

        //分页排序查询

        if (strOrderKey!="" &&strOrder!="")

        {

            strQuery += QString("ORDER BY %1 %2 LIMIT %3 OFFSET %4").arg(strOrderKey).arg(strOrder).arg(pagesize).arg(pagesize*pageno);

        }

        do

        {

            //先查出符合条件的总数量

            QSqlQuery countquery;

            //先删除数据库中的数据

            countquery.prepare(sqlcount);

            if (!countquery.exec()

                || !countquery.next())

            {

                QSqlError error = countquery.lastError();

                errorCode = error.type();

                msg = error.text();

                LOG_ERROR("query alarmInfo count failed,msg:%s", msg.toStdString().c_str());

                break;

            }

            quint64 totalCount = countquery.record().value(0).toULongLong();

            if (0 >= totalCount)

            {

                errorCode = 0;

                break;

            }

            QSqlQuery query;

            query.prepare(strQuery);

            if (!query.exec())

            {

                QSqlError error = query.lastError();

                errorCode = error.type();

                msg = error.text();

                break;

            }

            QVariantList dataList;

            while (query.next())

            {

                QSqlRecord record = query.record();

                int column = record.count();

     

                QVariantMap data;

                for (int i = 0; i < column; i++)

                {

                    data.insert(record.fieldName(i), record.value(i));

                }

                dataList.append(data);

            }

            //QVariantMap replyData;

            replyData.insert("totalCount", totalCount);

            replyData.insert("data", dataList);

            errorCode = 0;

        } while (0);

        return errorCode;

    }

    3.3   对比总结

    对比项

    常规增删改查操作

    基于模板的操作方法

    扩展性

    代码量

    开发效率

    灵活性

    通过对比可以知道,常规的增删改查操作需要针对具体的条件组织SQL语句,扩展性差,代码量大,而且对于不同的表格需要编写不同的函数接口,开发效率低下,灵活性差。而基于模板的操作方法,对操作方法进行了抽象,确定了统一的规范和方法,不同的表格可以使用相同的接口进行数据库操作,代码的灵活性和扩展性强,开发效率高,只需要按照规范输入条件参数,函数就可以自动的组织SQL语句,进行数据库操作。

    自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html
  • 相关阅读:
    JAVA-类加载机制(2)-类加载的过程
    JAVA-类加载机制(1)-生命周期
    StarUML-详解
    JMS-mq-发布/订阅
    JMS-mq-点对点
    Spring-Transcation
    Session-Hibernate
    Session
    Git配置
    Maven配置
  • 原文地址:https://www.cnblogs.com/bclshuai/p/15560023.html
Copyright © 2011-2022 走看看