Qt 數(shù)據(jù)庫(kù)QSqlDatabase使用示例
記錄一些在QT中使用QSqlDatabase操作數(shù)據(jù)庫(kù)時(shí),需要注意的地方
創(chuàng)建數(shù)據(jù)庫(kù)
bool CDBOperatorAbstract::_openDBConn(CDatabaseConfig config)
{
QWriteLocker locker(&m_locker);
QSqlDatabase db;
if(QSqlDatabase::contains(m_connectionName))
{
db = QSqlDatabase::database(m_connectionName);
QStringList tables = db.tables();
if(db.isOpen() && tables.contains(config.m_databaseName))
{
m_isConnected = true;
return true;
}
}
else
{
// 此時(shí)目標(biāo)數(shù)據(jù)庫(kù)不一定存在,不指定數(shù)據(jù)庫(kù)名,會(huì)默認(rèn)連接到mysql的主數(shù)據(jù)庫(kù)(mysql數(shù)據(jù)庫(kù))
db = QSqlDatabase::addDatabase("QMYSQL",m_connectionName);
db.setHostName(config.m_hostAddress); // 數(shù)據(jù)庫(kù)服務(wù)器IP
db.setPort(config.m_port); // 端口號(hào)
db.setUserName(config.m_userName); // 用戶(hù)名
db.setPassword(config.m_userPwd); // 密碼
}
// 連接數(shù)據(jù)庫(kù)
if(!db.open())
{
qDebug() << db.lastError().text();
m_isConnected = false;
return false;
}
QSqlQuery query(db);
QString strSql = QString("CREATE DATABASE IF NOT EXISTS `%1`").arg(config.m_databaseName);
//執(zhí)行建表語(yǔ)句,若執(zhí)行成功
if(query.exec(strSql))
{
//若查詢(xún)語(yǔ)句有錯(cuò)
if(query.lastError().isValid())
{
qDebug()<< query.lastError().text();
m_isConnected = false;
return false;
}
}
else
{
m_isConnected = false;
return false;
}
// 確認(rèn)目標(biāo)數(shù)據(jù)庫(kù)創(chuàng)建成功,關(guān)閉之前打開(kāi)的默認(rèn)數(shù)據(jù)庫(kù)
db.close();
// 重新設(shè)置連接的數(shù)據(jù)庫(kù)名
db.setDatabaseName(config.m_databaseName);
// 重新打開(kāi)數(shù)據(jù)庫(kù)
if(!db.open())
{
m_isConnected = false;
return false;
}
else
{
m_isConnected = true;
return true;
}
}
在上述創(chuàng)建數(shù)據(jù)庫(kù)的代碼中有幾個(gè)需要注意的地方:
1、一個(gè)QSqlDatabase對(duì)象表示的是一個(gè)數(shù)據(jù)庫(kù)連接,而不是字面上的數(shù)據(jù)庫(kù)(數(shù)據(jù)庫(kù)連接與數(shù)據(jù)庫(kù)的關(guān)系是:一個(gè)數(shù)據(jù)庫(kù)連接可以通過(guò)修改配置連接到多個(gè)數(shù)據(jù)庫(kù),一個(gè)數(shù)據(jù)庫(kù)也可以有多個(gè)數(shù)據(jù)庫(kù)連接)
2、addDatabase()方法需要指定數(shù)據(jù)庫(kù)驅(qū)動(dòng)類(lèi)型,如MySQL、SQLite……,如果沒(méi)有指定連接名,將默認(rèn)使用defaultConnection作為連接名。對(duì)于同一個(gè)連接,重復(fù)調(diào)用addDatabase(),會(huì)提示:
QSqlDatabasePrivate::addDatabase: duplicate connection name
‘qt_sql_default_connection’, old connection removed.
3、removeDatabase()刪除數(shù)據(jù)庫(kù)連接,需要在確保所有QSqlQuery查詢(xún)操作執(zhí)行完畢并且銷(xiāo)毀,否則會(huì)提示:
QSqlDatabasePrivate::removeDatabase: connection ‘qt_sql_default_connection’ is still in use, all queries will cease to work.
4、在進(jìn)行數(shù)據(jù)庫(kù)連接時(shí),目標(biāo)數(shù)據(jù)庫(kù)可能還不存在,這時(shí)候可以不指定數(shù)據(jù)庫(kù)名進(jìn)行連接,此會(huì)將連接到數(shù)據(jù)庫(kù)服務(wù)器的主數(shù)據(jù)庫(kù),例如我使用的是MySQL數(shù)據(jù)庫(kù)服務(wù)器,就會(huì)連接到mysql數(shù)據(jù)庫(kù)

5、數(shù)據(jù)庫(kù)連接建立成功后,創(chuàng)建目標(biāo)數(shù)據(jù)庫(kù)(不存在時(shí)才創(chuàng)建),確保目標(biāo)數(shù)據(jù)庫(kù)創(chuàng)建成功后,先關(guān)閉之前的數(shù)據(jù)庫(kù)連接,設(shè)置數(shù)據(jù)庫(kù)名稱(chēng)后再重新打開(kāi)。(只有重新打開(kāi)數(shù)據(jù)庫(kù)連接,數(shù)據(jù)庫(kù)配置才會(huì)生效)
多線程使用數(shù)據(jù)庫(kù)
QSqlDatabase是非線程安全的,意味著在多線程環(huán)境下同時(shí)使用同一個(gè)數(shù)據(jù)庫(kù)連接對(duì)象可能會(huì)導(dǎo)致競(jìng)態(tài)條件和數(shù)據(jù)一致性問(wèn)題。因此,每個(gè)線程最好都維護(hù)一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)連接,并且在同一個(gè)線程中創(chuàng)建、使用和關(guān)閉數(shù)據(jù)庫(kù)連接。如果數(shù)據(jù)庫(kù)連接有父對(duì)象,它和父對(duì)象也必須在同一個(gè)線程。
一般用QMap來(lái)管理線程和對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接,可以用QMap<QThread*,QSqlDatabase*>來(lái)存儲(chǔ),也可以用QMap<QThread*,QString>來(lái)存儲(chǔ)(存連接名)
由于程序可能在各個(gè)地方操作數(shù)據(jù)庫(kù),為了讓數(shù)據(jù)庫(kù)連接的創(chuàng)建和使用保持在同一個(gè)線程中,可以用QMetaObject::invokeMethod()將數(shù)據(jù)庫(kù)的創(chuàng)建、使用、關(guān)閉都移動(dòng)到數(shù)據(jù)庫(kù)連接所在的線程中
bool CDBOperatorAbstract::checkIsInWorkThread()
{
if(QThread::currentThread() == this->m_pThread)
return true;
else
return false;
}
bool CDBOperatorAbstract::openDBConn(CDatabaseConfig config)
{
if(checkIsInWorkThread())
{
return _openDBConn(config);
}
else
{
bool isOk = false;
QMetaObject::invokeMethod(this,"_openDBConn",Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool,isOk),
Q_ARG(CDatabaseConfig,config));
return isOk;
}
}
用BlockingQueuedConnection的連接方式,會(huì)將目標(biāo)函數(shù)放在接收者的生存線程中執(zhí)行,并且阻塞發(fā)送者所在的線程,直到目標(biāo)函數(shù)執(zhí)行完畢。
增刪改查
numRowsAffected()這個(gè)函數(shù)返回最后一個(gè)執(zhí)行的 SQL 查詢(xún)語(yǔ)句所影響的行數(shù)。通常用于 INSERT、UPDATE 或 DELETE 查詢(xún)之后,用來(lái)確定有多少行受到了影響。返回值是一個(gè)整數(shù)。
lastInsertId()這個(gè)函數(shù)用于在主鍵自增的情況下,獲取最后一次 INSERT 操作生成的主鍵,返回值為QVariant類(lèi)型,需要根據(jù)主鍵實(shí)際的類(lèi)型進(jìn)行轉(zhuǎn)換。
size()這個(gè)函數(shù)用于獲取當(dāng)前查詢(xún)結(jié)果集中的記錄數(shù)。例如執(zhí)行 SELECT 查詢(xún)后需要確定返回的記錄數(shù)量。返回值是一個(gè)整數(shù)。
isValid()這個(gè)函數(shù)用于檢查 QSqlQuery 對(duì)象是否有效,即它是否正常地初始化以執(zhí)行 SQL 查詢(xún)。
到此這篇關(guān)于Qt 數(shù)據(jù)庫(kù)QSqlDatabase使用示例的文章就介紹到這了,更多相關(guān)Qt QSqlDatabase內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ LeetCode1945題解字符串轉(zhuǎn)化后的各位數(shù)字之和
這篇文章主要為大家介紹了C++ LeetCode1945題解字符串轉(zhuǎn)化后的各位數(shù)字之和示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
C++中vector迭代器失效問(wèn)題的原因及解決方案
迭代器(iterator)是一種用于遍歷數(shù)據(jù)集合的的對(duì)象,它提供了一種訪問(wèn)數(shù)據(jù)集合中元素的方式,而無(wú)需暴露數(shù)據(jù)集合內(nèi)部的細(xì)節(jié),使用迭代器,我們可以對(duì)數(shù)據(jù)集合中的每個(gè)元素進(jìn)行處理,本文介紹了C++中關(guān)于vector迭代器失效問(wèn)題的原因及解決方案,需要的朋友可以參考下2024-09-09
vs2022重新編譯opencv-python?cuda加速時(shí)報(bào)錯(cuò)的問(wèn)題解決
本文主要介紹了vs2022重新編譯opencv-python?cuda加速時(shí)報(bào)錯(cuò),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
C++的sstream標(biāo)準(zhǔn)庫(kù)詳細(xì)介紹
以下是對(duì)C++中的的sstream標(biāo)準(zhǔn)庫(kù)進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下2013-09-09
C++中STL的優(yōu)先隊(duì)列priority_queue詳解
這篇文章主要介紹了C++中STL的優(yōu)先隊(duì)列priority_queue詳解,今天講一講優(yōu)先隊(duì)列(priority_queue),實(shí)際上,它的本質(zhì)就是一個(gè)heap,我從STL中扒出了它的實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-08-08

