头文件
#ifndef DATABASECOMMON_H
#define DATABASECOMMON_H
#include <QObject>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QMutex>
class DatabaseCommon
: public QObject
{
Q_OBJECT
public:
void setDatabase(QSqlDatabase db);
void setDatabaseName(QString dbName);
void setUserName(QString userName);
void setPassword(QString password);
virtual bool openDatabase() = 0;
void closeDatabase();
bool execNormalSQL(const QString &sqlString);
bool execSelect(const QString &sqlString, QSqlQueryModel &model);
bool execTransaction(const QString &sqlString);
bool execTransaction(const QStringList &sqlStrings);
private:
DatabaseCommon(const DatabaseCommon&) = delete;
DatabaseCommon& operator=(const DatabaseCommon&) = delete;
protected:
explicit DatabaseCommon(QObject *parent = nullptr){}
virtual ~DatabaseCommon();
QSqlDatabase mDatabase;
QString mDatabaseName = "";
QString mUserName = "";
QString mPassword = "";
QMutex mMutex;
};
class SysRunDatabase : public DatabaseCommon
{
Q_OBJECT
public:
static SysRunDatabase& Instance()
{
static SysRunDatabase mInstance;
return mInstance;
}
bool openDatabase() override;
protected:
explicit SysRunDatabase(QObject *parent = nullptr){}
~SysRunDatabase() override {}
private:
SysRunDatabase(const SysRunDatabase&) = delete;
SysRunDatabase& operator=(const SysRunDatabase&) = delete;
};
#endif
CPP文件
#include "databasecommon.h"
#include <QDebug>
#include <QSqlQuery>
#include <QFile>
#include <QException>
#include <QSqlError>
#include <QMutexLocker>
DatabaseCommon::~DatabaseCommon()
{
closeDatabase();
}
void DatabaseCommon::setDatabase(QSqlDatabase db)
{
QMutexLocker locker(&mMutex);
this->mDatabase = db;
}
void DatabaseCommon::setDatabaseName(QString dbName)
{
QMutexLocker locker(&mMutex);
this->mDatabaseName = dbName;
}
void DatabaseCommon::setUserName(QString userName)
{
QMutexLocker locker(&mMutex);
this->mUserName = userName;
}
void DatabaseCommon::setPassword(QString password)
{
QMutexLocker locker(&mMutex);
this->mPassword = password;
}
bool SysRunDatabase::openDatabase()
{
QMutexLocker locker(&mMutex);
if(!QFile::exists(mDatabaseName))
{
qCritical() << "not exist " << mDatabaseName;
return false;
}
mDatabase.setDatabaseName(mDatabaseName);
mDatabase.setUserName(mUserName);
mDatabase.setPassword(mPassword);
if(!mDatabase.open())
{
qCritical() << "open failed."<< mDatabase.lastError().text();
return false;
}
return true;
}
void DatabaseCommon::closeDatabase()
{
mDatabase.close();
}
bool DatabaseCommon::execNormalSQL(const QString &sqlString)
{
QMutexLocker locker(&mMutex);
if(!mDatabase.isOpen())
{
qCritical() << "Database is closed.";
return false;
}
try
{
QSqlQuery query(mDatabase);
if (!query.exec(sqlString))
{
throw query.lastError();
}
return true;
}
catch (const QSqlError &error)
{
qCritical() << "Error:" << error.text();
return false;
}
}
bool DatabaseCommon::execSelect(const QString &sqlString, QSqlQueryModel &model)
{
QMutexLocker locker(&mMutex);
if(!mDatabase.isOpen())
{
qCritical() << "Database is closed.";
return false;
}
if(!sqlString.startsWith("SELECT", Qt::CaseInsensitive))
{
qCritical() << "Unsupported operation: " << sqlString;
return false;
}
try
{
model.setQuery(sqlString, mDatabase);
return true;
}
catch (const QException &ex)
{
qCritical() << "Exception on model.setQuery: " << ex.what();
qCritical() << model.lastError().text();
return false;
}
}
bool DatabaseCommon::execTransaction(const QString &sqlString)
{
QMutexLocker locker(&mMutex);
if(!mDatabase.isOpen())
{
qCritical() << "Database is closed.";
return false;
}
if(sqlString.startsWith("SELECT", Qt::CaseInsensitive))
{
qCritical() << "Unsupported operation: " << sqlString;
return false;
}
if (!mDatabase.transaction())
{
qCritical() << "Failed to begin transaction:" << mDatabase.lastError().text();
return false;
}
QSqlQuery query(mDatabase);
try
{
if (!query.exec(sqlString))
{
throw query.lastError();
}
if (sqlString.trimmed().startsWith("UPDATE", Qt::CaseInsensitive) && query.numRowsAffected() == 0)
{
qWarning() << "Warning: No rows affected by:" << sqlString;
}
if (!mDatabase.commit())
{
throw mDatabase.lastError();
}
return true;
}
catch (const QSqlError &error)
{
if (!mDatabase.rollback())
{
qCritical() << "Failed to rollback transaction:" << mDatabase.lastError().text();
}
qCritical() << "Transaction failed at command:" << query.lastQuery();
qCritical() << "Error:" << error.text();
return false;
}
}
bool DatabaseCommon::execTransaction(const QStringList &sqlStrings)
{
QMutexLocker locker(&mMutex);
if(!mDatabase.isOpen())
{
qCritical() << "Database is closed.";
return false;
}
if (!mDatabase.transaction())
{
qCritical() << "Failed to begin transaction:" << mDatabase.lastError().text();
return false;
}
QSqlQuery query(mDatabase);
try
{
foreach (const QString &sql, sqlStrings)
{
if (!query.exec(sql))
{
throw query.lastError();
}
if (sql.trimmed().startsWith("UPDATE", Qt::CaseInsensitive) && query.numRowsAffected() == 0)
{
qWarning() << "Warning: No rows affected by:" << sql;
}
}
if (!mDatabase.commit())
{
throw mDatabase.lastError();
}
return true;
}
catch (const QSqlError &error)
{
if (!mDatabase.rollback())
{
qCritical() << "Failed to rollback transaction:" << mDatabase.lastError().text();
}
qCritical() << "Transaction failed at command:" << query.lastQuery();
qCritical() << "Error:" << error.text();
return false;
}
}
使用示例
QSqlDatabase::addDatabase("QSQLITE", "SysRun");
SysRunDatabase::Instance().setDatabase(QSqlDatabase::database("SysRun", false));
SysRunDatabase::Instance().setDatabaseName("123.db");
if(!SysRunDatabase::Instance().openDatabase())
{
return false;
}