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;
}
}