SQLite(sql)是一款開源輕量級的數(shù)據(jù)庫軟件,不需要server,可以集成在其他軟件中,非常適合嵌入式系統(tǒng)。
Qt5以上版本可以直接使用SQLite(Qt自帶驅(qū)動)。
QT += sql
#include <QSqlDatabase>#include <QSqlError>#include <QSqlQuery>
檢查連接、添加數(shù)據(jù)庫驅(qū)動、設(shè)置數(shù)據(jù)庫名稱、數(shù)據(jù)庫登錄用戶名、密碼。
QSqlDatabase database;if (QSqlDatabase::contains("qt_sql_default_connection")){ database = QSqlDatabase::database("qt_sql_default_connection");}else{ database = QSqlDatabase::addDatabase("QSQLITE"); database.setDatabaseName("MyDataBase.db"); database.setUserName("XingYeZhiXia"); database.setPassword("123456");}
上述代碼解釋:
(1)第一行中,建立了一個QSqlDatabase
對象,后續(xù)的操作要使用這個對象。
(2)if
語句用來檢查指定的連接(connection)是否存在。這里指定的連接名稱(connection name)是qt_sql_default_connection
,這是Qt默認(rèn)連接名稱。實(shí)際使用時,這個名稱可以任意取。如果判斷此連接已經(jīng)存在,那么QSqlDatabase::contains()
函數(shù)返回true。此時,進(jìn)入第一個分支,QSqlDatabase::database()
返回這個連接。
(3)如果這個連接不存在,則進(jìn)入else
分支,需要創(chuàng)建連接,并添加數(shù)據(jù)庫。在else
分支第一行,addDatabase()
的參數(shù)QSQLITE
是SQLite對應(yīng)的驅(qū)動名,不能改。而且需要注意的是,addDatabase()
的第二個參數(shù)被省略了,第二個參數(shù)的默認(rèn)參數(shù)就是上面提到的Qt默認(rèn)連接名稱qt_sql_default_connection
。如果需要使用自定義的連接名稱(如果程序需要處理多個數(shù)據(jù)庫文件的話就會這樣),則應(yīng)該加入第二個參數(shù),例如
database = QSqlDatabase::addDatabase("QSQLITE", "my_sql_connection);
這個時候,如果在另一個地方需要判斷my_sql_connection
連接是否存在,就應(yīng)該使用if (QSqlDatabase::contains("my_sql_connection"))
。
(4)else
分支第二行中,setDatabaseName()
的參數(shù)是數(shù)據(jù)庫文件名。如果這個數(shù)據(jù)庫不存在,則會在后續(xù)操作時自動創(chuàng)建;如果已經(jīng)存在,則后續(xù)的操作會在已有的數(shù)據(jù)庫上進(jìn)行。
(5)else
分支后面兩行,設(shè)置用戶名和密碼。用戶名,密碼都可以隨便取,也可以省略。
使用open()
打開數(shù)據(jù)庫,并判斷是否成功。注意,在第一步檢查連接是否存在時,如果連接存在,則在返回這個連接的時候,會默認(rèn)將數(shù)據(jù)庫打開。
if (!database.open()){ qDebug() << "Error: Failed to connect database." << database.lastError();}else{ // do something}
如果打開成功,則進(jìn)入else分支。對數(shù)據(jù)庫的操作都需要在else分支中進(jìn)行。
數(shù)據(jù)庫操作完成后,最好關(guān)閉。
database.close();
對數(shù)據(jù)庫進(jìn)行操作需要用到QSqlQuery類,操作前必須定義一個對象。下面舉例說明操作方法。操作需要使用SQLite語句,本文中的幾個例子會使用幾個常用的語句,關(guān)于SQLite語句的具體信息請參考SQLite相關(guān)資料。
例1:創(chuàng)建表格
創(chuàng)建一個名為student的表格,表格包含三列,第一列是id,第二列是名字,第三列是年齡。
QSqlQuery sql_query;QString create_sql = "create table student (id int primary key, name varchar(30), age int)";sql_query.prepare(create_sql);if(!sql_query.exec()){ qDebug() << "Error: Fail to create table." << sql_query.lastError();}else{ qDebug() << "Table created!";}
代碼解釋:
(1)第一行定義一個QSqlQuery
對象。
(2)第二行是一個QString
,其中的內(nèi)容是SQLite語句。對數(shù)據(jù)庫的操作,都是用SQLite的語句完成的,把這些指令以QString類型,通過prepare
函數(shù),保存在QSqlQuery對象中。也可將指令,以QString形式直接寫在exec()
函數(shù)的參數(shù)中,例如:
sql_query.exec("create table student (id int primary key, name varchar(30), age int)");
創(chuàng)建表格語句:create table <table_name> (f1 type1, f2 type2,…);
create table
是創(chuàng)建表格的語句,也可用大寫CREATE TABLE
;student是表格的名稱,可以任意?。焕ㄌ栔惺潜砀竦母袷?,上述指令表明,表格中有三列,第一列的名稱(表頭)是id,這一列儲存的數(shù)據(jù)類型是int,第二列名稱是name,數(shù)據(jù)類型是字符數(shù)組,最多有30個字符(和char(30)的區(qū)別在于,varchar的實(shí)際長度是變化的,而char的長度始終是給定的值),第三列的名稱是age,數(shù)據(jù)類型是int。
如果sql_query.exec()
執(zhí)行成功,則創(chuàng)建表格成功。
例2:插入數(shù)據(jù)
在剛才創(chuàng)建的表格中,插入一行數(shù)據(jù)。
QString insert_sql = "insert into student values (?, ?, ?)";sql_query.prepare(insert_sql);sql_query.addBindValue(max_id+1);sql_query.addBindValue("Wang");sql_query.addBindValue(25);if(!sql_query.exec()){ qDebug() << sql_query.lastError();}else{ qDebug() << "inserted Wang!";}if(!sql_query.exec("INSERT INTO student VALUES(3, \"Li\", 23)")){ qDebug() << sql_query.lastError();}else{ qDebug() << "inserted Li!";}
插入語句:insert into <table_name> values (value1, value2,…);
insert into
是插入語句,student是表格名稱,values()是要插入的數(shù)據(jù)。這里,我們插入了2組數(shù)據(jù)。插入第一組數(shù)據(jù)的時候,用addBindValue
來替代語句中的?
,替代的順序與addBindValue
調(diào)用的順序相同。插入第二組數(shù)據(jù)的時候,則是直接寫出完整語句。
例3:更新數(shù)據(jù)(修改數(shù)據(jù))
QString update_sql = "update student set name = :name where id = :id";sql_query.prepare(update_sql);sql_query.bindValue(":name", "Qt");sql_query.bindValue(":id", 1);if(!sql_query.exec()){ qDebug() << sql_query.lastError();}else{ qDebug() << "updated!";}
語句:update <table_name> set <f1=value1>, <f2=value2>… where <expression>;
更新(修改)的語句是update...set...
,其中student是表格名稱,name是表頭名稱(即第二列),:name是待定的變量,where用于確定是哪一組數(shù)據(jù),:id也是待定變量。bindValue(" ", " ")
函數(shù)用來把語句中的待定變量換成確定值。
例4:查詢數(shù)據(jù)
(1)查詢部分?jǐn)?shù)據(jù)
QString select_sql = "select id, name from student";if(!sql_query.exec(select_sql)){ qDebug()<<sql_query.lastError();}else{ while(sql_query.next()) { int id = sql_query.value(0).toInt(); QString name = sql_query.value(1).toString(); qDebug()<<QString("id:%1 name:%2").arg(id).arg(name); }}
語句select <f1>, <f2>, ... from <table_name>;
select是查詢指令;<f1>
等等是要查詢的變量(即表頭),中間用逗號隔開;from ...指定表格。
上述語句是說查詢student表中的 id 和 name 。執(zhí)行查詢之后,用sql_query.value(int)
來獲得數(shù)據(jù)。同樣地,value(0)
表示第一個數(shù)據(jù),即 id,value(1)
表示name。注意:value()
函數(shù)的返回值類型是QVariant
,因此要用toInt()
等函數(shù)轉(zhuǎn)換成特定的類型。
(2)查詢?nèi)繑?shù)據(jù)
QString select_all_sql = "select * from student";sql_query.prepare(select_all_sql);if(!sql_query.exec()){ qDebug()<<sql_query.lastError();}else{ while(sql_query.next()) { int id = sql_query.value(0).toInt(); QString name = sql_query.value(1).toString(); int age = sql_query.value(2).toInt(); qDebug()<<QString("id:%1 name:%2 age:%3").arg(id).arg(name).arg(age); }}
語句select * from <table_name>;
查詢所有數(shù)據(jù)用 * 表示。用while(sql_query.next())
用來遍歷所有行。同樣用value()
獲得數(shù)據(jù)。
(3)查詢最大id
QString select_max_sql = "select max(id) from student";int max_id = 0;sql_query.prepare(select_max_sql);if(!sql_query.exec()){ qDebug() << sql_query.lastError();}else{ while(sql_query.next()) { max_id = sql_query.value(0).toInt(); qDebug() << QString("max id:%1").arg(max_id); }}
這個就是在語句中用max
來獲取最大值。
例5:刪除與清空
(1)刪除一條數(shù)據(jù)
QString delete_sql = "delete from student where id = ?";sql_query.prepare(delete_sql);sql_query.addBindValue(0);if(!sql_query.exec()){ qDebug()<<sql_query.lastError();}else{ qDebug()<<"deleted!";}
語句delete from <table_name> where <f1> = <value>
delete用于刪除條目,用where給出限定條件。例如此處是刪除 id = 0的條目。
(2)清空表格(刪除所有)
QString clear_sql = "delete from student";sql_query.prepare(clear_sql);if(!sql_query.exec()){ qDebug() << sql_query.lastError();}else{ qDebug() << "table cleared";}
這里沒有用where給出限制,就會刪除所有內(nèi)容。