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


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

    步骤 1: 创建 Singleton Database Class

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

    #ifndef DATABASEMANAGER_H  
    #define DATABASEMANAGER_H  
    
    #include   
    #include   
    #include   
    #include   
    
    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 类。

    #include   
    #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 能够创建一个全局唯一的静态实例,并在第一个使用这个实例时进行初始化。例如:

    #include   
    #include   
    
    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 管理数据库连接

    #include   
    #include   
    #include   
    #include   
    
    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 提供的一个有用的宏,能够用于懒汉式全局静态变量的创建。
    线程安全,确保在多线程环境下的安全访问。
    自动清理,简化了资源管理。
    适合用在需要全局共享资源的场景中,如数据库连接、配置对象等。
    这种设计模式结合了简单性和安全性,特别在复杂的多线程程序中尤为重要。

  • 相关阅读:
    【实战】使用 Web Animations API 实现一个精确计时的时钟
    三十二、Fluent收敛判断标准及方法
    JavaScript中JSON和Bom对象模型
    [密码学入门]仿射密码(Affine)
    70. 爬楼梯 (进阶),322. 零钱兑换,279.完全平方数
    Windows环境部署ZLMediaKit,支持WebRTC
    Visual Studio Code 从英文界面切换中文
    MySQL表的约束
    Pyinstaller安装与使用
    一文搞定防盗链设计
  • 原文地址:https://blog.csdn.net/qq_71286244/article/details/141098019