QT初学者如何进行单例模式的封装(基于sqlite3的数据库语法),以及什么是单例模式,单例模式的优点,单例模式中的结构设计原因

1.什么是数据库单例模式单例?

数据库单例是一种设计模式,用于确保在整个应用程序中只存在一个数据库连接实例

2.为什么要使用单例模式?(优点好处)

节省资源:数据库连接是一种比较昂贵的资源,通过数据库单例模式可以确保在整个应用程序生命周期内只创建一个数据库连接实例,避免频繁地打开和关闭连接,从而节省资源。

提高性能:数据库单例可以减少因频繁连接数据库而引起的性能损耗,通过重复使用同一个数据库连接实例,减少了连接建立和断开的开销,提高了数据库操作的效率。

维护一致性:数据库单例模式可以确保整个应用程序使用的都是同一个数据库连接实例,避免了数据不一致性和并发访问问题,简化了数据管理和维护。

简化代码:通过数据库单例模式,可以将数据库连接实例的获取逻辑封装在单例类中,使得在整个应用程序中可以方便地获取到唯一的数据库连接实例,简化了代码逻辑。

方便扩展:如果以后需要对数据库连接进行优化或者添加缓存等功能,通过数据库单例模式可以很容易地对单例类进行扩展,而不影响应用程序其他部分的代码。

总的来说,数据库单例模式在 MVC 框架中能够提供资源节约、性能优化、数据一致性、代码简化和方便扩展等优点,是一个常见且有效的设计模式。

3.如何实现单例模式?

(1)将数据库db文件和数据库头文件导入进项目工程中的bin目录下

(2)我们需要将构造函数、析构函数全部都私有化,并创建一个静态的私有指针

构造、析构私有化的原因:

构造函数私有化:通过将构造函数私有化,可以防止在类外部直接创建对象,只能通过单例类内部的特定方法来获取单例对象。这样可以避免了在外部意外地创建多个对象,确保了单例对象的唯一性(这边和上面数据库单例优点中的唯一性相呼应)

析构函数私有化:同样地,将析构函数私有化可以防止在类外部直接销毁对象,只能通过单例类内部的特定方法来释放单例对象。这样可以确保在程序结束时正确释放资源,避免了意外地销毁单例对象,导致资源泄露或程序异常。

因此,通过将构造函数和析构函数私有化,单例类能够更好地控制单例对象的创建和销毁过程,确保了单例对象的唯一性和正确性,是单例模式的一种常见实现方式。

定义静态私有指针的原因:

存储单例对象的唯一实例:静态私有指针在类内部被声明为私有,因此只能在单例类的内部访问。这个指针通常被用来存储单例对象的实例,确保在整个应用程序中只存在一个实例。

控制单例对象的访问:静态私有指针通常会与公有的静态方法(如 getInstance())结合使用。通过这些公有方法,可以控制单例对象的访问方式,确保单例对象只能通过特定的方法获取,从而实现单例对象的唯一性和控制访问权限。

延迟单例对象的实例化:静态私有指针可以在需要时延迟实例化单例对象,而不是在程序启动时立即创建。这种延迟实例化的方式可以节省资源,只有在第一次需要使用单例对象时才会创建它。

便于释放资源:静态私有指针通常与析构函数一起使用,用于在程序结束时释放单例对象所占用的资源。通过单例指针的存在,可以方便地在析构函数中对单例对象进行销毁和资源释放,确保程序的正确性和资源的正确释放。

(3)我们要创建一个公共类外访问点getInstance() 方法和手动释放静态成员的函数releaseInstance()

这样我们可以实现在程序运行期间只创建一个 qtSingleton 类的对象实例,并且可以通过 getInstance() 方法获取该实例,通过 releaseInstance() 方法释放该实例。这种设计确保了全局范围内只存在一个对象实例,从而提高了资源利用效率和数据的一致性。

代码实现:

#ifndef QTSINGLETON_H
#define QTSINGLETON_H

#include "sqlite3.h"
#include <QString>
class qtSingleton
{
private:
    //构造函数私有化,构造函数在这边是用来打开数据库的
    qtSingleton();

    //析构函数私有化,析构函数这边是用来关闭数据库的
    ~qtSingleton();

    //定义一个静态的私有指针
    static qtSingleton* dbinstance;
    sqlite3 *pdb;
public:
    //定义一个公有的静态成员函数,这边是用来当做接口用的,用来对数据库进行增删改查的接口
    static qtSingleton* getInstance();

    //定义一个关闭数据库的静态成员函数
    static void releaseInstance();

    //封装增删改函数
    /**
     * @brief doInDelUp
     * @param sql
     * @return 
     */
    int doInDelUp(QString sql);

    //封装查询函数
    /**
     * @brief doSelect
     * @param sql
     * @param qres
     * @param row
     * @param col
     * @return 
     */
    int doSelect(QString sql,char **&qres,int &row,int &col);
};

#endif // QTSINGLETON_H
#include "model/qtsingleton.h"
#include <QDebug>
qtSingleton *qtSingleton::dbinstance = nullptr;

qtSingleton::qtSingleton()
{
    int res = sqlite3_open("pro.db",&pdb);//这边填入一个已经在bin目录下的数据库
    if(res == SQLITE_OK)
    {
        //qDebug()<<"open db.sql success";
    }
    else {
        qDebug()<<sqlite3_errmsg(pdb);
        qDebug()<<sqlite3_errcode(pdb);
    }
}

qtSingleton::~qtSingleton()
{
    sqlite3_close(this->pdb);
    //qDebug()<<"close db success";
}

qtSingleton *qtSingleton::getInstance()
{
    if(qtSingleton::dbinstance == nullptr)
    {
        qtSingleton::dbinstance = new qtSingleton();
        //qDebug()<<"第一次";
    }
    else {
        //qDebug()<<"第二次";
    }
    return  qtSingleton::dbinstance;
}

void qtSingleton::releaseInstance()
{
    if(qtSingleton::dbinstance!= nullptr)
    {
        delete qtSingleton::dbinstance;
        qtSingleton::dbinstance =nullptr;
    }
}

int qtSingleton::doInDelUp(QString sql)
{
    char *errmsg=nullptr;
    int res = sqlite3_exec(this->pdb,sql.toUtf8(),nullptr,nullptr,&errmsg);
    //res结果只表示操作成功
    if(res != SQLITE_OK)
    {
            qDebug()<<sqlite3_errmsg(pdb);
            qDebug()<<sqlite3_errcode(pdb);
    }
    else {
        return -1;//成功
    }

}

int qtSingleton::doSelect(QString sql, char **&qres, int &row, int &col)
{
    //qDebug()<<"qtSingleton::doSelect-------------";
    char *errmsg=nullptr;
    int res = sqlite3_get_table(this->pdb,sql.toUtf8(),&qres,&row,&col,&errmsg);
    if(res != SQLITE_OK)
    {
        qDebug()<<"qtSingleton::doSelect-------------没查到";
        return -1;

    }
    else {
        return 1;
    }

}

m_pDbProcPic = new CDBProcess("sqlserver"); m_pDbProc->openDB("mysvr", "mydb", "myusername", "mypwd"); m_pDbProcPic = new CDBProcess("mysql"); m_pDbProc->openDB("localhost", "mydb", "root", "password"); m_pDbProcPic = new CDBProcess("access"); m_pDbProc->openDB("", strMDB, "sa", "password"); m_pDbProcPic = new CDBProcess("sqlite"); m_pDbProcPic->openDB("", "mysqlitedb"); CDBProcess使用说明 构造函数: CDBProcess(const QString strType); 参数:为数据库类型,不区分大小写,支持的类型有 sqlite mysql access sqlserver 例: CDBProcess db("sqlite"); -------------------------------------------------- 打开数据库 bool openDB(const QString strSvrName, //服务器名 const QString strDBname, //数据库名 const QString strUserID="", //用户名 const QString strUserPwd=""); //密码 打开数据库成功,返回true,否则返回false 对于sqlite,只有strDBname有效,其它参数忽略,如db.openDB("", "mysqlite.db") 对于MS Access数据库,strSvrName为空,用户名默认为"sa",如db.openDB("", "myaccess.mdb"); 对MSAccess数据库,也可通过一个UDL文件,打开,如db.openDB("my.udl", ""); mysql和sqlserver,就是各个参数依次提供,如db.openDB("svr1", "mydb", "user1", "abcd"); ----------------------------------------------------- 关闭数据库,CDBProcess析构时,亦会自动关闭数据库 void closeDB(); //db.closeDB(); ------------------------------------------------------ 执行Sql语句 bool excuteSQL(const QString); ------------------------------------------------------- 打开记录集 bool openRecordsetBySql(const QString strSql, //Sql语句 int idx = -1); //记录集id,用于标识记录集,默认值为-1 例: db.openRecordsetBySql("SELECT * FROM TB1", 5); 打开一个记录集,标识号为5,后面操作这个记录集,也要提供这个标识号 -------------------------------------------------------- 关闭记录集 void closeRecordset(int idx = -1); 例: db.closeRecordset(5); 关闭之前打开的标识为5的记录集 ----------------------------------- 数据库是否处在打开状态 bool isOpen() const; ------------------------------------ 记录集游标是否在结尾,参数为记录集标识 bool recEOF(int idx = -1) const; 例:bool b = db.RecBOF(5); ------------------------------------ 记录集游标是否在第一条记录之前,参数为记录集标识 bool recBOF(int idx = -1) const; ---------------------------------------- 删除一个表 bool dropTable(const QString); --------------------------------------------- 读取标识为idx记录集的当前记录的各字段值,方法如示例: bool getFieldsValueFromRec(int idx, const char* szFldInfo, ...) const; int iSN; QString strName; double dHeight; QDateTime dt; QByteArray ba; db.getFieldsValueFromRec(5, //记录集id "sn%d", &iSN, //字段名加类型 sn为字段名%d表示整型,&iSN传入指针,保存返回字段值 "name%s", &strName, //字段名加类型 name为字段名%s表示字符串(QString) "height&f", &dHeight, //字段名加类型 height为字段名%f表示小数(double) "birthday%t", &dt, //字段名加类型 birthday为字段名%t表示时间(QDateTime) "photo%b", &ba, //字段名加类型 photo为字段名%b表示二进制流(QByteArray) CDBProcess::szEnd); //结束标志,"|" 执行后,各字段值就保存在iSN, strName等变量了。 参数:第一个参数为记录集id 后面可变参数,字段%类型标识,用于保存返回值的指针, 类型标识:%d-int %s-QString %f-double %t-QDateTime %b-QByteArray --------------------------------------------------------------------------- 向一个数据表填加一条记录 bool addFieldsValueToTbl(const QString strTbl, const char* szFldInfo, ...); 参数:第一个参数strTbl,为表名 后面是可变参数,为"字段%类型标识",值(或指针),注int,double类型直接传值,其它传指针 例: db.addFieldsValueToTbl("TB1", //表名 "sn%d", iSN, //字段名加类型 sn为字段名%d表示整型,iSN传入值 "name%s", &strName, //字段名加类型 name为字段名%s表示字符串(QString), 传入QString变量指针 "height&f", dHeight, //字段名加类型 height为字段名%f表示小数(double),dHeight传入值 "birthday%t", &dt, //字段名加类型 birthday为字段名%t表示时间(QDateTime),传入指针 "photo%b", &ba, //字段名加类型 photo为字段名%b表示二进制流(QByteArray),传入指针 CDBProcess::szEnd); //结束标志,"|" ----------------------------------------------------------- 修改表符合WHERE子句条件的记录 bool updateTblFieldsValue(const QString strTbl, QString strWhere, const char * szFldInfo, ... ); strTbl表名 strWhere SQL WHERE子句,如"WHERE sn=20" const char * szFldInfo, ...可变参数,同addFieldsValueToTbl 例: db.updateTblFieldsValue("TB1", "WHERE sn=20", "height&f", dHeight, "photo%b", &ba, CDBProcess::szEnd); ---------------------------------------------------------------- 以下几个函数分别是获取记录数,和记录光标移动。参数为记录集标识 long getRecordCount(int idx = -1) const; bool moveFirst(int idx = -1) const; bool movePrevious(int idx = -1) const; bool moveNext(int idx = -1) const; bool moveLast(int idx = -1) const; bool moveTo(int n, int idx = -1) const; -------------------------------------------------------------------- 返回数据库名 QString getDbName() const; ------------------------ 以下几个函数未验证 bool execStoreProcOfArgList(int idx, const QString strStoreProc, const char* szFldsInfo, ...); bool exexProc(const QString strStoreProc, QString str1, QString& str2); bool transaction(); bool commit(); bool rollback();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值