在 Qt 中使用单例模式操作数据库,可以确保在整个应用程序中只有一个数据库连接被创建。这通常通过将数据库连接封装在一个单例类中来实现。下面是一个详细的代码示例,演示如何在 Qt 中实现这个模式。
首先,我们需要定义一个数据库单例类。
#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
接下来,我们可以在需要操作数据库的任何地方使用 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();
}
Q_GLOBAL_STATIC 是 Qt 提供的一个宏,用于定义全局静态变量。在多线程环境中,它可以用于确保只在第一次访问时初始化变量,并且在程序终止时自动销毁。这个宏的运用能够有效简化单例模式的实现,并保证线程安全。
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;
}
Q_GLOBAL_STATIC 是线程安全的,它使用内部的锁机制确保在多线程环境中只会有一个线程创建实例,其他线程将等待创建完成后获取该实例。
与老式的单例模式不同,Q_GLOBAL_STATIC 提供了一种懒汉式的初始化方式,即只有在首次调用时才会创建实例,这样就避免了在程序启动时就进行不必要的开销。
使用 Q_GLOBAL_STATIC 定义的实例会在程序退出时自动调用析构函数。开发者不需要手动管理资源,降低了内存泄漏的风险。
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;
}
Q_GLOBAL_STATIC 是 Qt 提供的一个有用的宏,能够用于懒汉式全局静态变量的创建。
线程安全,确保在多线程环境下的安全访问。
自动清理,简化了资源管理。
适合用在需要全局共享资源的场景中,如数据库连接、配置对象等。
这种设计模式结合了简单性和安全性,特别在复杂的多线程程序中尤为重要。