QSqlQuery 是 Qt SQL 模块中的一个核心类,它代表一个对数据库执行的 SQL 语句,你可以把它想象成一个“命令游标”或“语句执行器”,它允许你执行 SQL 查询(SELECT)、更新(INSERT, UPDATE, DELETE)、管理事务等。

核心概念
在使用 QSqlQuery 之前,必须确保已经:
- 加载数据库驱动:Qt 支持多种数据库(如 SQLite, MySQL, PostgreSQL, ODBC 等),你需要告诉 Qt 你要使用哪种驱动。
- 建立数据库连接:通过
QSqlDatabase类创建一个到特定数据库的连接。
下面我们以最常见的 SQLite 为例,因为它不需要安装额外的数据库服务器,非常适合学习和演示。
基本环境设置
确保你已经安装了 PyQt5 或 PySide2/PySide6。
pip install PyQt5
导入必要的模块:

import sys from PyQt5.QtSql import QSqlDatabase, QSqlQuery from PyQt5.QtWidgets import QApplication, QMessageBox
建立数据库连接
这是使用任何 QSql 类的第一步。
def create_connection():
"""创建并返回一个到SQLite数据库的连接"""
db = QSqlDatabase.addDatabase('QSQLITE') # 指定使用SQLite驱动
db.setDatabaseName('example.db') # 设置数据库文件名,如果不存在会自动创建
if not db.open():
QMessageBox.critical(None, "错误", f"无法连接到数据库: {db.lastError().text()}")
return False
return True
QSqlQuery 的主要用法
一旦建立了连接,你就可以创建 QSqlQuery 对象来执行SQL了。
1 执行非查询语句 (DDL/DML)
这类语句不返回结果集,CREATE, INSERT, UPDATE, DELETE。
直接在构造函数中执行

query = QSqlQuery("CREATE TABLE IF NOT EXISTS users ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, "
"age INTEGER)", db)
if not query.isActive():
print(f"创建表失败: {query.lastError().text()}")
else:
print("表 'users' 创建成功或已存在。")
使用 prepare() 和 exec() (推荐,尤其适用于参数化查询)
这种方式更安全、更高效,可以防止SQL注入。
# 准备SQL语句
query = QSqlQuery(db)
query.prepare("INSERT INTO users (name, age) VALUES (:name, :age)")
# 绑定参数
query.bindValue(":name", "Alice")
query.bindValue(":age", 30)
# 执行
if not query.exec_():
print(f"插入数据失败: {query.lastError().text()}")
else:
print("插入数据成功。")
# 可以重复绑定并执行,插入另一条数据
query.bindValue(":name", "Bob")
query.bindValue(":age", 25)
query.exec_()
print("插入数据成功。")
2 执行查询语句
对于 SELECT 语句,你需要遍历结果集。
query = QSqlQuery("SELECT id, name, age FROM users", db)
# 1. 检查查询是否成功执行
if not query.isActive():
print(f"查询失败: {query.lastError().text()}")
else:
# 2. 遍历结果集
print("\n--- 用户列表 ---")
while query.next(): # 移动到下一条记录,如果存在则返回True
# 3. 获取字段值
# 方法一:按列号获取 (从0开始)
id = query.value(0)
name = query.value(1)
age = query.value(2)
# 方法二:按列名获取 (更清晰,推荐)
# id = query.value("id")
# name = query.value("name")
# age = query.value("age")
print(f"ID: {id}, 姓名: {name}, 年龄: {age}")
3 更新和删除数据
更新和删除数据与插入类似,使用 UPDATE 和 DELETE 语句。
# 更新数据
query = QSqlQuery(db)
query.prepare("UPDATE users SET age = :new_age WHERE name = :name")
query.bindValue(":new_age", 31)
query.bindValue(":name", "Alice")
if query.exec_():
print(f"成功更新了 {query.numRowsAffected()} 条记录。")
else:
print(f"更新失败: {query.lastError().text()}")
# 删除数据
query.prepare("DELETE FROM users WHERE name = :name")
query.bindValue(":name", "Bob")
if query.exec_():
print(f"成功删除了 {query.numRowsAffected()} 条记录。")
else:
print(f"删除失败: {query.lastError().text()}")
4 事务处理
事务可以确保一组数据库操作要么全部成功,要么全部失败,保证数据的一致性。
def transaction_example():
if not create_connection():
return
db = QSqlDatabase.database()
query = QSqlQuery(db)
try:
# 1. 开始事务
db.transaction()
# 2. 执行多个操作
query.prepare("INSERT INTO users (name, age) VALUES (?, ?)") # ?是另一种占位符
query.addBindValue("Charlie")
query.addBindValue(40)
query.exec_()
query.prepare("INSERT INTO users (name, age) VALUES (?, ?)")
query.addBindValue("David")
query.addBindValue(35)
query.exec_()
# 3. 如果所有操作都成功,则提交事务
db.commit()
print("事务提交成功!")
except Exception as e:
# 4. 如果发生任何错误,则回滚事务
db.rollback()
print(f"发生错误,事务已回滚: {e}")
# 关闭连接
db.close()
完整示例代码
下面是一个将上述所有功能整合在一起的完整、可运行的示例。
import sys
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget, QVBoxLayout, QPushButton, QTextEdit
class DatabaseDemo(QWidget):
def __init__(self):
super().__init__()
self.db = None
self.initUI()
def initUI(self):
self.setWindowTitle('QSqlQuery 示例')
self.setGeometry(300, 300, 500, 400)
self.layout = QVBoxLayout()
self.btn_connect = QPushButton('连接数据库并创建表')
self.btn_insert = QPushButton('插入数据')
self.btn_query = QPushButton('查询数据')
self.btn_update = QPushButton('更新数据')
self.btn_delete = QPushButton('删除数据')
self.btn_transaction = QPushButton('事务示例')
self.text_output = QTextEdit()
self.text_output.setReadOnly(True)
self.layout.addWidget(self.btn_connect)
self.layout.addWidget(self.btn_insert)
self.layout.addWidget(self.btn_query)
self.layout.addWidget(self.btn_update)
self.layout.addWidget(self.btn_delete)
self.layout.addWidget(self.btn_transaction)
self.layout.addWidget(self.text_output)
self.setLayout(self.layout)
self.btn_connect.clicked.connect(self.connect_and_create_table)
self.btn_insert.clicked.connect(self.insert_data)
self.btn_query.clicked.connect(self.query_data)
self.btn_update.clicked.connect(self.update_data)
self.btn_delete.clicked.connect(self.delete_data)
self.btn_transaction.clicked.connect(self.transaction_example)
def connect_and_create_table(self):
self.db = QSqlDatabase.addDatabase('QSQLITE')
self.db.setDatabaseName('example.db')
if not self.db.open():
self.log_message(f"无法连接到数据库: {self.db.lastError().text()}")
return
query = QSqlQuery(self.db)
create_table_sql = """
CREATE TABLE IF NOT EXISTS employees (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
position TEXT,
salary REAL
)
"""
if not query.exec(create_table_sql):
self.log_message(f"创建表失败: {query.lastError().text()}")
else:
self.log_message("数据库连接成功,表 'employees' 已准备就绪。")
def log_message(self, message):
self.text_output.append(message)
def insert_data(self):
if not self.check_connection():
return
query = QSqlQuery(self.db)
query.prepare("INSERT INTO employees (name, position, salary) VALUES (?, ?, ?)")
# 插入第一条
query.addBindValue("张三")
query.addBindValue("软件工程师")
query.addBindValue(12000.50)
if not query.exec_():
self.log_message(f"插入失败: {query.lastError().text()}")
return
# 插入第二条
query.addBindValue("李四")
query.addBindValue("项目经理")
query.addBindValue(25000.00)
query.exec_()
self.log_message(f"成功插入 {query.numRowsAffected()} 条记录。")
def query_data(self):
if not self.check_connection():
return
query = QSqlQuery("SELECT * FROM employees", self.db)
if not query.isActive():
self.log_message(f"查询失败: {query.lastError().text()}")
return
self.log_message("\n--- 员工列表 ---")
while query.next():
id = query.value("id")
name = query.value("name")
position = query.value("position")
salary = query.value("salary")
self.log_message(f"ID: {id}, 姓名: {name}, 职位: {position}, 薪资: {salary:.2f}")
def update_data(self):
if not self.check_connection():
return
query = QSqlQuery(self.db)
query.prepare("UPDATE employees SET salary = salary * 1.1 WHERE position = ?")
query.addBindValue("软件工程师")
if query.exec_():
self.log_message(f"成功更新了 {query.numRowsAffected()} 名软件工程师的薪资。")
else:
self.log_message(f"更新失败: {query.lastError().text()}")
def delete_data(self):
if not self.check_connection():
return
query = QSqlQuery(self.db)
query.prepare("DELETE FROM employees WHERE name = ?")
query.addBindValue("李四")
if query.exec_():
self.log_message(f"成功删除了 {query.numRowsAffected()} 条记录。")
else:
self.log_message(f"删除失败: {query.lastError().text()}")
def transaction_example(self):
if not self.check_connection():
return
self.db.transaction()
query = QSqlQuery(self.db)
try:
query.prepare("INSERT INTO employees (name, position, salary) VALUES (?, ?, ?)")
query.addBindValue("王五")
query.addBindValue("测试工程师")
query.addBindValue(8000.00)
query.exec_()
# 模拟一个错误,看看事务是否会回滚
# 如果取消下面这行的注释,事务将失败,之前的插入也会被撤销
# self.db.rollback()
# raise Exception("手动触发错误")
self.db.commit()
self.log_message("事务提交成功:新员工王五已入职。")
except Exception as e:
self.db.rollback()
self.log_message(f"事务失败,已回滚: {e}")
def check_connection(self):
if not self.db or not self.db.isOpen():
self.log_message("错误:数据库未连接。")
return False
return True
def closeEvent(self, event):
if self.db and self.db.isOpen():
self.db.close()
event.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = DatabaseDemo()
demo.show()
sys.exit(app.exec_())
| 功能 | 方法 | 说明 |
|---|---|---|
| 创建实例 | QSqlQuery(sql, db) 或 QSqlQuery(db) |
可以直接带SQL创建,或先创建再准备。 |
| 准备语句 | query.prepare(sql) |
使用参数化查询(name 或 )的首选方法。 |
| 绑定参数 | query.bindValue(":name", "Alice") 或 query.addBindValue("Alice") |
为预语句中的占位符赋值。 |
| 执行语句 | query.exec_() |
执行准备好的或直接的SQL语句。 |
| 检查状态 | query.isActive() |
检查上一个操作是否成功执行。 |
| 获取错误 | query.lastError().text() |
获取上一个操作的错误信息。 |
| 获取影响行数 | query.numRowsAffected() |
获取 INSERT, UPDATE, DELETE 影响的行数。 |
| 遍历结果 | query.next() |
将游标移动到下一条记录,返回是否存在下一条。 |
| 获取值 | query.value(0) 或 query.value("name") |
获取当前记录的指定列值。 |
| 事务 | db.transaction(), db.commit(), db.rollback() |
通过 QSqlDatabase 对象管理事务。 |
QSqlQuery 功能强大且灵活,是 Qt 应用程序中进行数据库操作的基础,掌握它的用法对于开发数据驱动的桌面应用至关重要。
