qt 使用单例模式操作数据库

在 Qt 中使用单例模式操作数据库,可以确保在整个应用程序中只有一个数据库连接被创建。这通常通过将数据库连接封装在一个单例类中来实现。下面是一个详细的代码示例,演示如何在 Qt 中实现这个模式。

步骤 1: 创建 Singleton Database Class

首先,我们需要定义一个数据库单例类。

cpp 复制代码
#ifndef DATABASEMANAGER_H  
#define DATABASEMANAGER_H  

#include <QSqlDatabase>  
#include <QSqlQuery>  
#include <QSqlError>  
#include <QDebug>  

class DatabaseManager {  
public:  
    static DatabaseManager& getInstance() {  
        static DatabaseManager instance; // Guaranteed to be destroyed.  
        return instance;                 // Instantiated on first use.  
    }  

    // 禁用拷贝构造和赋值操作  
    DatabaseManager(const DatabaseManager&) = delete;  
    void operator=(const DatabaseManager&) = delete;  

    bool openConnection() {  
        db = QSqlDatabase::addDatabase("QSQLITE"); // 使用 SQLite 数据库  
        db.setDatabaseName("my_database.db"); // 数据库文件名  

        if (!db.open()) {  
            qDebug() << "Database error occurred:" << db.lastError().text();  
            return false;  
        }  
        return true;  
    }  

    void closeConnection() {  
        if (db.isOpen()) {  
            db.close();  
        }  
    }  

    QSqlQuery executeQuery(const QString &queryStr) {  
        QSqlQuery query(db);  
        if (!query.exec(queryStr)) {  
            qDebug() << "Query error occurred:" << query.lastError().text();  
        }  
        return query;  
    }  

private:  
    DatabaseManager() {  
        // 初始化数据库连接  
        if (!openConnection()) {  
            qDebug() << "Failed to connect to the database.";  
        }  
    }  

    ~DatabaseManager() {  
        closeConnection();  
    }  

    QSqlDatabase db;  
};  


#endif // DATABASEMANAGER_H  

步骤 2: 使用 DatabaseManager 类

接下来,我们可以在需要操作数据库的任何地方使用 DatabaseManager 类。

cpp 复制代码
#include <QCoreApplication>  
#include "DatabaseManager.h"  

int main(int argc, char *argv[]) {  
    QCoreApplication a(argc, argv);  

    DatabaseManager& dbManager = DatabaseManager::getInstance();  
    
    // 执行 SQL 查询  
    QSqlQuery query = dbManager.executeQuery("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");  

    // 插入一些数据  
    query = dbManager.executeQuery("INSERT INTO users (name) VALUES ('Alice')");  
    query = dbManager.executeQuery("INSERT INTO users (name) VALUES ('Bob')");  

    // 查询数据  
    query = dbManager.executeQuery("SELECT * FROM users");  
    while (query.next()) {  
        qDebug() << "User ID:" << query.value(0).toInt() << ", Name:" << query.value(1).toString();  
    }  

    return a.exec();  
}  

3. 说明

  1. Singleton Design Pattern:
  • getInstance() 方法确保只会创建一个 DatabaseManager 的实例。
  • 拷贝构造函数和赋值运算符被删除,以防止创建第二个实例。
  1. 数据库操作:
  • openConnection() 方法负责打开数据库连接。
  • closeConnection() 方法在析构时关闭连接。
  • executeQuery() 方法用于执行 SQL 查询,并返回结果。
  1. 主程序:
  • 在 main() 函数中,我们通过调用 DatabaseManager::getInstance() 获取数据库管理器的实例,并执行一些简单的数据库操作。

4. 注意

  • 确保在使用前配置好 Qt SQL 模块(如 SQLite)。
  • 适当处理数据库错误以增强程序健壮性。
  • 这里的示例使用 SQLite 数据库,你可以根据需要更改为其他数据库类型,调整连接参数。

5. 使用Q_GLOBAL_STATIC

Q_GLOBAL_STATIC 是 Qt 提供的一个宏,用于定义全局静态变量。在多线程环境中,它可以用于确保只在第一次访问时初始化变量,并且在程序终止时自动销毁。这个宏的运用能够有效简化单例模式的实现,并保证线程安全。

  1. 宏的基本用法

Q_GLOBAL_STATIC 能够创建一个全局唯一的静态实例,并在第一个使用这个实例时进行初始化。例如:

cpp 复制代码
#include <QGlobalStatic>  
#include <QDebug>  

class MyClass {  
public:  
    MyClass() {  
        qDebug() << "MyClass initialized.";  
    }  

    void doSomething() {  
        qDebug() << "Doing something.";  
    }  
};  

Q_GLOBAL_STATIC(MyClass, myGlobalInstance)  

void function() {  
    myGlobalInstance()->doSomething(); // 访问全局实例  
}  

int main() {  
    function(); // 第一次调用时,实例化 MyClass  
    function(); // 后续调用,将使用已经创建的实例  

    return 0;  
}  
  1. 深入分析
  • 2.1 线程安全

Q_GLOBAL_STATIC 是线程安全的,它使用内部的锁机制确保在多线程环境中只会有一个线程创建实例,其他线程将等待创建完成后获取该实例。

  • 2.2 懒汉式初始化

与老式的单例模式不同,Q_GLOBAL_STATIC 提供了一种懒汉式的初始化方式,即只有在首次调用时才会创建实例,这样就避免了在程序启动时就进行不必要的开销。

  • 2.3 自动清理

使用 Q_GLOBAL_STATIC 定义的实例会在程序退出时自动调用析构函数。开发者不需要手动管理资源,降低了内存泄漏的风险。

  1. 实际应用

Q_GLOBAL_STATIC 适合用于配置实例、资源管理、全局状态等场景。例如,你可以用它来管理数据库连接、日志记录器等。

示例:使用 Q_GLOBAL_STATIC 管理数据库连接

cpp 复制代码
#include <QGlobalStatic>  
#include <QSqlDatabase>  
#include <QSqlError>  
#include <QDebug>  

class Database {  
public:  
    Database() {  
        db = QSqlDatabase::addDatabase("QSQLITE");  
        db.setDatabaseName("app.db");  
        if (!db.open()) {  
            qDebug() << "Database error:" << db.lastError().text();  
        }  
    }  

    void query(const QString &sql) {  
        QSqlQuery query(db);  
        if (!query.exec(sql)) {  
            qDebug() << "Query error:" << query.lastError().text();  
        }  
    }  

private:  
    QSqlDatabase db;  
};  

Q_GLOBAL_STATIC(Database, globalDatabase)  

void executeDatabaseQuery(const QString &sql) {  
    globalDatabase()->query(sql);  
}  

int main() {  
    executeDatabaseQuery("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)");  
    executeDatabaseQuery("INSERT INTO users (name) VALUES ('Alice')");  
    return 0;  
}  
  1. 总结

Q_GLOBAL_STATIC 是 Qt 提供的一个有用的宏,能够用于懒汉式全局静态变量的创建。

线程安全,确保在多线程环境下的安全访问。

自动清理,简化了资源管理。

适合用在需要全局共享资源的场景中,如数据库连接、配置对象等。

这种设计模式结合了简单性和安全性,特别在复杂的多线程程序中尤为重要。

相关推荐
老邓计算机毕设13 小时前
SSM学生选课系统xvbna(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·学生选课系统·ssm 框架·高校教学管理
钱彬 (Qian Bin)13 小时前
项目实践17—全球证件智能识别系统(开发基于LabelMe标注的可视化审核接口)
qt·fastapi·全球证件识别
枷锁—sha14 小时前
【PortSwigger Academy】SQL 注入绕过登录 (Login Bypass)
数据库·sql·学习·安全·网络安全
逍遥德16 小时前
PostgreSQL 中唯一约束(UNIQUE CONSTRAINT) 和唯一索引(UNIQUE INDEX) 的核心区别
数据库·sql·postgresql·dba
工业甲酰苯胺16 小时前
字符串分割并展开成表格的SQL实现方法
数据库·sql
科技块儿16 小时前
IP定位技术:游戏反外挂体系中的精准识别引擎
数据库·tcp/ip·游戏
衫水16 小时前
[特殊字符] MySQL 常用指令大全
数据库·mysql·oracle
卓怡学长16 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
小句17 小时前
SQL中JOIN语法详解 GROUP BY语法详解
数据库·sql
阿杰 AJie18 小时前
MySQL 里给表添加索引
数据库·mysql