当前位置: 首页 > news >正文

Qt项目锻炼——TODO清单(二)

Qt里有很多类和函数我也不知道,只能利用好Qt Assistant当场查找。
在这里插入图片描述

实现 TaskModel 类

TaskModel 类继承自 QSqlTableModel,用于处理与数据库中任务表的交互,以及对任务数据的显示和操作。

头文件

class TaskModel : public QSqlTableModel 
{  Q_OBJECT
public:  // 列索引枚举类型,是模型中表的列名enum Columns{IdColumn = 0,  TitleColumn,  DescriptionColumn,  PriorityColumn,  DueDateColumn,  CompletedColumn,  CreatedAtColumn  };  explicit TaskModel(QObject* parent = nullptr);  // 自定义数据显示  QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;  bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;  // 任务操作  bool addTask(const Task& task);  bool updateTask(const Task& task);  bool deleteTask(int taskId);  QList<Task> getAllTasks() const;  // 过滤方法  void setFilterByStatus(bool showCompleted, bool showOverdue);  void setSearchText(const QString& text);  
};

源文件


TaskModel::TaskModel(QObject* parent) : QSqlTableModel(parent)
{setTable("tasks");setEditStrategy(QSqlTableModel::OnManualSubmit);select(); //更新模型里的数据
}QVariant TaskModel::data(const QModelIndex& index, int role) const
{if (role == Qt::DisplayRole){if (index.column() == PriorityColumn){int priority = QSqlTableModel::data(index, role).toInt();switch (priority){case Task::Low: return "Low";case Task::Medium: return "Medium";case Task::High: return "High";default: return "";}}}return QSqlTableModel::data(index, role);
}bool TaskModel::setData(const QModelIndex& index, const QVariant& value, int role)
{return QSqlTableModel::setData(index, value, role);
}bool TaskModel::addTask(const Task& task)
{QSqlQuery query; // Ensure QSqlQuery is fully included and initialized// Prepare the SQL query to insert a new taskquery.prepare("INSERT INTO tasks (title, description, priority, due_date, completed) ""VALUES (:title, :description, :priority, :due_date, :completed)");// Bind the values to the query parametersquery.bindValue(":title", task.title());query.bindValue(":description", task.description());query.bindValue(":priority", task.priority());query.bindValue(":due_date", task.dueDate().toString("yyyy-MM-dd"));query.bindValue(":completed", task.completed());if (query.exec()){select();return true;}else{qDebug() << "Failed to add task:" << query.lastError().text();return false;}
}bool TaskModel::updateTask(const Task& task)
{QSqlQuery query; // Ensure QSqlQuery is fully included and initializedquery.prepare("UPDATE tasks SET title = :title, description = :description, ""priority = :priority, due_date = :due_date, completed = :completed ""WHERE id = :id");query.bindValue(":id", task.id());query.bindValue(":title", task.title());query.bindValue(":description", task.description());query.bindValue(":priority", task.priority());query.bindValue(":due_date", task.dueDate().toString("yyyy-MM-dd"));query.bindValue(":completed", task.completed());if (query.exec()){select();return true;}else{qDebug() << "Failed to update task:" << query.lastError().text();return false;}
}bool TaskModel::deleteTask(int taskId)
{QSqlQuery query; // Ensure QSqlQuery is fully included and initializedquery.prepare("DELETE FROM tasks WHERE id = :id");query.bindValue(":id", taskId);if (query.exec()){select();return true;}else{qDebug() << "Failed to delete task:" << query.lastError().text();return false;}
}QList<Task> TaskModel::getAllTasks() const
{QList<Task> tasks;for (int i = 0; i < rowCount(); ++i){int id = data(index(i, IdColumn)).toInt();QString title = data(index(i, TitleColumn)).toString();QString description = data(index(i, DescriptionColumn)).toString();int priority = data(index(i, PriorityColumn)).toInt();QDate dueDate = QDate::fromString(data(index(i, DueDateColumn)).toString(), "yyyy-MM-dd");bool completed = data(index(i, CompletedColumn)).toBool();tasks.append(Task(id, title, description, static_cast<Task::Priority>(priority), dueDate, completed));}return tasks;
}void TaskModel::setFilterByStatus(bool showCompleted, bool showOverdue)
{QString filter;if (!showCompleted){filter += "completed = 0";}if (showOverdue){if (!filter.isEmpty()){filter += " AND ";}filter += "due_date < CURDATE() AND completed = 0";}setFilter(filter);select();
}void TaskModel::setSearchText(const QString& text)
{QString filter = QString("title LIKE '%%1%' OR description LIKE '%%1%'").arg(text);setFilter(filter);select();
}

补充

QSqlTableModel 是 Qt 框架中用于数据库操作的模型类,它继承自 QAbstractTableModel,专为表格数据与 SQL 数据库之间的交互设计。以下是它与普通 QAbstractTableModel(或其子类)的主要区别及使用方法:

QSqlTableModel介绍

  1. 数据来源

    • QSqlTableModel:直接连接数据库表,数据自动从 SQL 查询获取。
    • 普通 TableModel:需要手动管理内存中的数据(如 QListQVector)。
  2. 数据操作

    • QSqlTableModel:支持数据库级的增删改查(CRUD),通过 insertRow()setData()removeRow() 等方法自动生成 SQL 语句。
    • 普通 TableModel:需手动实现数据操作逻辑,如在内存中添加/删除项,并手动触发数据变更信号(如 dataChanged())。
  3. 性能

    • QSqlTableModel:适合中小型数据集,大数据量时可能因频繁数据库查询导致性能下降。
    • 普通 TableModel:适合完全在内存中处理的数据,性能取决于实现方式。
  4. 同步机制

    • QSqlTableModel:支持自动或手动提交更改到数据库(通过 submitAll()revertAll())。
    • 普通 TableModel:无内置同步机制,需自行实现与外部数据源的同步。

QSqlTableModel 使用方法

1. 基本初始化
#include <QSqlTableModel>
#include <QTableView>// 创建模型并连接到数据库表
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("tasks");  // 指定数据库表名
model->setEditStrategy(QSqlTableModel::OnManualSubmit);  // 设置编辑策略
model->select();  // 执行 SQL 查询,加载数据// 将模型应用到视图
QTableView *view = new QTableView;
view->setModel(model);
view->show();
2. 编辑策略

控制数据何时提交到数据库:

  • QSqlTableModel::OnFieldChange:每次单元格修改立即提交。
  • QSqlTableModel::OnRowChange:切换行时提交当前行的修改。
  • QSqlTableModel::OnManualSubmit:手动调用 submitAll() 提交所有更改。
3. 数据操作
// 添加新行
model->insertRow(model->rowCount());
model->setData(model->index(model->rowCount()-1, 0), "New Task");  // 设置数据
model->submitAll();  // 提交更改到数据库// 修改数据
model->setData(model->index(0, 1), "Updated Description");
model->submitAll();// 删除选中行
QModelIndexList selected = view->selectionModel()->selectedRows();
for (int i = 0; i < selected.size(); ++i) {model->removeRow(selected.at(i).row());
}
model->submitAll();
4. 过滤与排序
// 过滤数据(相当于 SQL WHERE 子句)
model->setFilter("completed = 1");  // 只显示已完成的任务
model->select();// 排序数据(相当于 SQL ORDER BY)
model->setSort(2, Qt::AscendingOrder);  // 按第3列升序排序
model->select();
5. 高级用法
  • 自定义数据显示:重写 data() 方法,自定义单元格显示格式。
  • 关联多表:使用 QSqlRelationalTableModel 处理外键关联。
  • 事务处理:结合 QSqlDatabase::transaction()submitAll() 确保数据一致性。

何时选择 QSqlTableModel?

  • 当数据主要存储在数据库中,且需要直接操作数据库表时。
  • 当需要快速实现数据库与界面的双向同步时。
  • 当业务逻辑简单,无需复杂的数据处理时。

何时选择普通 TableModel?

  • 当数据来源非数据库(如网络、文件)时。
  • 当需要复杂的数据处理或自定义逻辑时。
  • 当性能是关键因素,需要优化内存使用时。

总结

QSqlTableModel 是数据库操作的便捷工具,适合快速开发数据库应用;而普通 TableModel 提供更高的灵活性,适合复杂场景。根据项目需求选择合适的模型,可大幅提高开发效率。

在 Qt 的模型/视图(Model/View)架构中,QAbstractItemModel::data()核心虚函数,负责为视图提供指定索引(QModelIndex)和角色(Qt::ItemDataRole)的数据。它是模型与视图通信的桥梁,决定了数据如何在界面上显示和交互。

data函数

一、函数原型与参数

virtual QVariant QAbstractItemModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const;
  • 参数
    • index:指定数据项的位置(行、列、父项)。
    • role:指定数据的用途(如显示文本、编辑文本、图标等)。
  • 返回值
    • QVariant:存储任意类型的数据(需与角色类型匹配),无效数据返回 QVariant()

二、核心作用

  1. 数据复用:同一数据项可根据不同角色提供不同形式的数据。
    例如:

    • DisplayRole:显示为 "$100.00"(字符串)。
    • UserRole:存储为 100.0(浮点数,用于计算)。
  2. 视图渲染控制:视图根据角色获取数据并渲染。
    例如:

    • DecorationRoleQIcon 显示在项前。
    • FontRoleQFont 决定文本字体。
  3. 交互逻辑分离

    • 编辑操作(如 QLineEdit)使用 EditRole 的数据,而非 DisplayRole,避免格式干扰。

三、常用角色与返回值类型

角色用途常见返回类型
Qt::DisplayRole显示文本QString
Qt::EditRole编辑文本QString
Qt::DecorationRole图标/图像QIcon, QPixmap, QColor
Qt::ToolTipRole鼠标悬停提示QString
Qt::FontRole字体QFont
Qt::TextAlignmentRole文本对齐方式Qt::AlignmentFlag
Qt::BackgroundColorRole背景颜色QBrush
Qt::ForegroundRole前景颜色(文本颜色)QBrush
Qt::CheckStateRole复选框状态Qt::CheckState
Qt::UserRole用户自定义数据任意类型(如 int, QDate

四、实现示例

1. 简单表格模型(QAbstractTableModel 子类)
class MyTableModel : public QAbstractTableModel {
public:// 必须实现的三个虚函数int rowCount(const QModelIndex &parent = QModelIndex()) const override {return dataList.size();}int columnCount(const QModelIndex &parent = QModelIndex()) const override {return 3; // 3列}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (!index.isValid() || index.row() >= dataList.size())return QVariant();const auto &item = dataList[index.row()];switch (role) {case Qt::DisplayRole:case Qt::EditRole:switch (index.column()) {case 0: return item.name;      // 第1列:名称case 1: return item.age;       // 第2列:年龄case 2: return item.score;     // 第3列:分数default: return QVariant();}case Qt::ForegroundRole:if (item.score < 60)return QBrush(Qt::red);      // 分数不及格:红色文本return QBrush(Qt::black);case Qt::ToolTipRole:return QString("Name: %1\nAge: %2\nScore: %3").arg(item.name).arg(item.age).arg(item.score);case Qt::UserRole:return QVariant::fromValue(item); // 存储完整数据对象default:return QVariant();}}private:struct Item {QString name;int age;double score;};QList<Item> dataList;
};
2. 树形模型(QAbstractItemModel 子类)
QVariant MyTreeModel::data(const QModelIndex &index, int role) const {if (!index.isValid())return QVariant();TreeItem *item = static_cast<TreeItem*>(index.internalPointer());switch (role) {case Qt::DisplayRole:return item->data(index.column()); // 返回节点数据case Qt::DecorationRole:if (index.column() == 0) { // 第1列显示图标if (item->hasChildren())return folderIcon;elsereturn fileIcon;}return QVariant();case Qt::CheckStateRole:if (index.column() == 0) { // 第1列支持复选框return item->isChecked() ? Qt::Checked : Qt::Unchecked;}return QVariant();default:return QVariant();}
}

五、使用技巧

  1. 角色组合

    • 同一索引可针对不同角色返回不同数据。例如:
      if (role == Qt::DisplayRole)return QString::number(value);
      else if (role == Qt::EditRole)return value; // 编辑时返回原始数值,而非字符串
      
  2. 自定义角色

    • 使用 Qt::UserRole + n 定义自定义角色,存储特殊数据(如对象指针、ID)。
      enum CustomRoles {SortRole = Qt::UserRole + 1, // 用于排序的数值IdRole = Qt::UserRole + 2    // 存储唯一ID
      };// 在data()中实现
      case SortRole: return item.sortValue;
      case IdRole: return item.id;
      
  3. 性能优化

    • 避免在 data() 中执行耗时操作(如文件读取、网络请求)。
    • 缓存频繁访问的数据,减少重复计算。

六、常见问题

  1. 视图不显示数据

    • 检查 data() 是否为 Qt::DisplayRole 返回了有效数据。
    • 确保 rowCount()columnCount() 返回正确值。
  2. 编辑异常

    • 若编辑框显示异常,检查 EditRole 是否与 DisplayRole 兼容。
  3. 图标/颜色不生效

    • 确保 DecorationRole 返回 QIconQPixmapForegroundRole 返回 QBrush

总结

data() 函数是 Qt 模型的核心,通过角色机制实现了数据的多维度表达。理解并正确实现它,是开发灵活、高效 Qt 应用的关键。

QSqlQuery 是 Qt 框架中用于执行 SQL 语句和处理查询结果的核心类。它支持多种数据库操作,包括查询、插入、更新和删除等。以下是 QSqlQuery 的详细用法和最佳实践:

QSqlQuery

一、基本使用流程

1. 初始化与执行 SQL
// 假设已创建并打开数据库连接(如使用 QSqlDatabase::addDatabase())
QSqlQuery query;  // 默认使用默认数据库连接// 执行简单查询
bool success = query.exec("SELECT * FROM users");
if (!success) {qDebug() << "Query error:" << query.lastError().text();
}
2. 遍历查询结果
while (query.next()) {  // 逐行移动光标QString name = query.value(0).toString();  // 第1列数据(索引0)int age = query.value(1).toInt();          // 第2列数据qDebug() << "Name:" << name << "Age:" << age;
}
3. 使用参数化查询(防止 SQL 注入)
// 方式1:命名参数
query.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
query.bindValue(":name", "Alice");
query.bindValue(":age", 30);
query.exec();// 方式2:位置参数(使用 ? 占位符)
query.prepare("INSERT INTO users (name, age) VALUES (?, ?)");
query.addBindValue("Bob");
query.addBindValue(25);
query.exec();

二、高级功能

1. 批量插入数据
// 使用 ODBC 风格的批量插入(高效处理大量数据)
query.prepare("INSERT INTO users (name, age) VALUES (?, ?)");QVariantList names;
names << "Alice" << "Bob" << "Charlie";QVariantList ages;
ages << 30 << 25 << 35;query.addBindValue(names);
query.addBindValue(ages);if (!query.execBatch()) {qDebug() << "Batch error:" << query.lastError().text();
}
2. 执行 DDL 语句(创建表、索引等)
query.exec(R"(CREATE TABLE IF NOT EXISTS tasks (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,description TEXT,priority INTEGER DEFAULT 1,due_date DATE,completed BOOLEAN DEFAULT 0)
)");
3. 获取查询结果元数据
if (query.exec("SELECT * FROM tasks")) {QSqlRecord record = query.record();int columnCount = record.count();for (int i = 0; i < columnCount; ++i) {qDebug() << "Column" << i << "name:" << record.fieldName(i);qDebug() << "Column" << i << "type:" << record.field(i).typeName();}
}

三、错误处理

if (!query.exec("SELECT * FROM non_existent_table")) {QSqlError error = query.lastError();qDebug() << "Error:" << error.text();qDebug() << "SQL State:" << error.sqlState();qDebug() << "Database Text:" << error.databaseText();
}

四、事务处理

QSqlDatabase db = QSqlDatabase::database();
db.transaction();  // 开始事务QSqlQuery query;
query.exec("INSERT INTO logs (message) VALUES ('Transaction started')");if (/* 条件判断 */) {db.commit();  // 提交事务
} else {db.rollback();  // 回滚事务
}

五、在 TODO 系统中的应用示例

1. 添加任务
bool TodoManager::addTask(const QString &title, const QString &description, int priority, const QDate &dueDate) {QSqlQuery query;query.prepare("INSERT INTO tasks (title, description, priority, due_date) ""VALUES (:title, :desc, :priority, :dueDate)");query.bindValue(":title", title);query.bindValue(":desc", description);query.bindValue(":priority", priority);query.bindValue(":dueDate", dueDate);return query.exec();
}
2. 查询所有任务
QList<Task> TodoManager::getAllTasks() {QList<Task> tasks;QSqlQuery query("SELECT * FROM tasks ORDER BY due_date");while (query.next()) {Task task;task.id = query.value("id").toInt();task.title = query.value("title").toString();task.description = query.value("description").toString();task.priority = query.value("priority").toInt();task.dueDate = query.value("due_date").toDate();task.completed = query.value("completed").toBool();tasks.append(task);}return tasks;
}
3. 更新任务状态
bool TodoManager::markTaskCompleted(int taskId, bool completed) {QSqlQuery query;query.prepare("UPDATE tasks SET completed = :completed WHERE id = :id");query.bindValue(":completed", completed);query.bindValue(":id", taskId);return query.exec();
}

六、性能优化建议

  1. 使用预编译语句(Prepared Statements)
    避免重复解析 SQL 语句,提高批量操作效率:

    query.prepare("INSERT INTO items (name, price) VALUES (?, ?)");
    for (const auto &item : itemsList) {query.addBindValue(item.name);query.addBindValue(item.price);query.exec();
    }
    
  2. 批量提交数据
    在事务中执行多个操作,减少数据库提交次数:

    db.transaction();
    // 执行多个INSERT/UPDATE
    db.commit();
    
  3. 使用索引
    对查询频繁的字段(如日期、优先级)创建索引:

    CREATE INDEX idx_due_date ON tasks (due_date);
    

七、注意事项

  1. 数据类型转换
    QSqlQuery::value() 返回 QVariant,需正确转换类型:

    QDate date = query.value("due_date").toDate();  // 正确
    QDate date = query.value("due_date").toString();  // 错误!
    
  2. 跨平台兼容性
    不同数据库(如 SQLite、MySQL、PostgreSQL)对 SQL 语法支持略有差异,需注意兼容性。

  3. 资源管理
    QSqlQuery 对象析构时会自动释放相关资源,无需手动关闭。

总结

QSqlQuery 是 Qt 数据库编程的核心工具,通过以下步骤可高效使用:

  1. 执行 SQL 语句(exec()/prepare()
  2. 处理查询结果(next()/value()
  3. 绑定参数(bindValue()/addBindValue()
  4. 错误处理(lastError()
  5. 事务管理(transaction()/commit()/rollback()

结合参数化查询和事务处理,可确保数据操作的安全性和高效性。在你的 TODO 系统中,QSqlQuery 将是连接 UI 与数据库的关键桥梁。

QSqlQuery::bindValue() 是 Qt 中用于参数化查询的核心函数,它通过将 SQL 语句中的占位符与实际值绑定,实现安全高效的数据查询与操作。以下是对该函数的详细解析:

QSqlQuery::bindvalue函数

一、函数原型与参数

void QSqlQuery::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In);
  • 参数
    • placeholder:SQL 语句中的占位符名称(如 :name?)。
    • val:要绑定的值,使用 QVariant 支持任意数据类型。
    • paramType:参数类型(可选),默认为 QSql::In(输入参数)。
      • QSql::In:输入参数(用于查询条件)。
      • QSql::Out:输出参数(用于存储存储过程的返回值)。
      • QSql::InOut:输入输出参数。
      • QSql::Binary:二进制数据(如图片、文件)。

二、核心作用与优势

1. 防止 SQL 注入攻击

通过参数化查询,数据库会自动处理值中的特殊字符,避免恶意注入:

// 不安全的拼接(存在 SQL 注入风险)
QString name = userInput;  // 假设用户输入 "Robert'; DROP TABLE users; --"
query.exec("SELECT * FROM users WHERE name = '" + name + "'");// 安全的参数化查询
query.prepare("SELECT * FROM users WHERE name = :name");
query.bindValue(":name", userInput);  // 自动转义特殊字符
query.exec();
2. 自动类型转换

QVariant 会自动处理数据类型,无需手动格式化:

// 绑定日期类型
QDate dueDate = QDate::currentDate();
query.prepare("INSERT INTO tasks (title, due_date) VALUES (:title, :date)");
query.bindValue(":title", "Buy groceries");
query.bindValue(":date", dueDate);  // 自动转换为数据库支持的日期格式
3. 提高查询性能

预编译 SQL 语句后重复使用,避免数据库重复解析相同结构的 SQL:

query.prepare("INSERT INTO logs (message, timestamp) VALUES (:msg, :time)");for (const auto &msg : messages) {query.bindValue(":msg", msg);query.bindValue(":time", QDateTime::currentDateTime());query.exec();  // 仅参数变化,SQL 结构不变
}

三、使用示例

1. 命名占位符(推荐方式)
// SQL 语句中使用 :name 形式的占位符
query.prepare("INSERT INTO users (name, age, email) VALUES (:name, :age, :email)");
query.bindValue(":name", "Alice");
query.bindValue(":age", 30);
query.bindValue(":email", "alice@example.com");
query.exec();
2. 位置占位符(使用 ?)
// SQL 语句中使用 ? 占位符
query.prepare("UPDATE tasks SET title = ?, completed = ? WHERE id = ?");
query.bindValue(0, "Revise report");     // 第1个 ?
query.bindValue(1, true);                // 第2个 ?
query.bindValue(2, 5);                   // 第3个 ?
query.exec();
3. 处理 NULL 值
// 绑定可能为 NULL 的值
QString optionalDescription;  // 可能为空
query.prepare("INSERT INTO notes (content, attachment) VALUES (:content, :attach)");
query.bindValue(":content", "Meeting minutes");
query.bindValue(":attach", optionalDescription.isNull() ? QVariant(QVariant::String) : optionalDescription);
4. 存储过程中的输出参数
// 调用存储过程获取用户数量
query.prepare("CALL GetUserCount(:count)");
query.bindValue(":count", 0, QSql::Out);  // 输出参数
query.exec();int userCount = query.boundValue(":count").toInt();

四、在 TODO 系统中的应用

1. 添加新任务
bool TodoModel::addTask(const Task &task) {QSqlQuery query;query.prepare("INSERT INTO tasks (title, description, priority, due_date, completed) ""VALUES (:title, :desc, :priority, :dueDate, :completed)");query.bindValue(":title", task.title);query.bindValue(":desc", task.description);query.bindValue(":priority", static_cast<int>(task.priority));  // 枚举转 intquery.bindValue(":dueDate", task.dueDate);query.bindValue(":completed", task.completed);return query.exec();
}
2. 查询带条件的任务
QList<Task> TodoModel::searchTasks(const QString &keyword, bool showCompleted) {QList<Task> results;QSqlQuery query;query.prepare("SELECT * FROM tasks ""WHERE title LIKE :keyword ""AND (completed = :completed OR :showAll = 1)");query.bindValue(":keyword", "%" + keyword + "%");query.bindValue(":completed", showCompleted);query.bindValue(":showAll", showCompleted ? 1 : 0);if (query.exec()) {// 解析结果...}return results;
}

五、注意事项

  1. 占位符语法差异

    • 命名占位符(:name):适用于大多数数据库(如 SQLite、PostgreSQL)。
    • 位置占位符(?):适用于所有数据库,但需严格按顺序绑定值。
  2. 预编译与执行分离

    // 正确流程:先 prepare,再 bindValue,最后 exec
    query.prepare("SELECT * FROM users WHERE age > :min");
    query.bindValue(":min", 18);
    query.exec();
    
  3. 二进制数据处理

    QByteArray imageData;  // 图片数据
    query.bindValue(":image", imageData, QSql::Binary);  // 指定二进制类型
    
  4. 多次执行同一查询

    query.prepare("INSERT INTO items (name) VALUES (:name)");for (const auto &name : itemNames) {query.bindValue(":name", name);query.exec();  // 每次执行前重新绑定值query.finish();  // 可选:清除当前结果集
    }
    

六、常见问题与解决方案

问题原因分析解决方案
查询失败但无明确错误占位符名称与 bindValue() 不匹配
2. 数据类型不兼容
1. 检查占位符拼写和数量
2. 使用 QVariant::type() 确认类型兼容性
中文或特殊字符乱码未正确设置数据库连接编码在连接数据库前设置编码:db.setConnectOptions("MYSQL_OPT_CHARSET_NAME=utf8")
存储过程输出参数无值1. 未正确标记为 QSql::Out
2. 未在 exec() 后获取值
1. 确保参数类型正确
2. 通过 boundValue() 获取输出值

总结

bindValue() 是 Qt 数据库编程中确保安全性性能的关键函数,主要应用场景包括:

  1. 防止 SQL 注入(优先使用命名占位符)。
  2. 处理复杂数据类型(如日期、二进制)。
  3. 优化重复查询(预编译 SQL)。
  4. 存储过程参数传递。

在 TODO 系统中,建议对所有涉及用户输入的 SQL 语句(如搜索、添加任务)都使用 bindValue(),以避免安全风险并提升代码健壮性。

http://www.dtcms.com/a/267733.html

相关文章:

  • jmm--volatile
  • 前端面试专栏-算法篇:18. 查找算法(二分查找、哈希查找)
  • vue3 el-input el-select 非空校验
  • 大数据学习2:HIve
  • Linux进程管理:从基础到实战
  • Qt Ribbon效果界面
  • QT6 源(154)模型视图架构里的列表视图 QListView:先学习属性部分,
  • 认识Redis
  • Chat Model API
  • 60天python训练营打卡day52
  • 运算方法和运算器补充
  • 如何录制带备注的演示文稿(LaTex Beamer + Pympress)
  • Codeforces Round 919 (Div. 2) D. Array Repetition(分块,1900)
  • 【深圳大学机器学习】实验一:PCA算法
  • 【ACL系列论文写作指北15-如何进行reveiw】-公平、公正、公开
  • 大数据学习1:Hadoop单机版环境搭建
  • Redis 哨兵模式部署--docker版本
  • C++面试-auto,auto,auto 的区别
  • 【ESP32】2.多任务处理
  • 相机位姿估计
  • 使用接口测试工具类Postman和浏览器的差异
  • C++ 语言特性31 - 协程介绍(2)
  • 用 Turbo Vision 2 为 Qt 6 控制台应用创建 TUI 字符 MainFrame
  • Redis性能优化
  • 五、Python新特性指定类型用法
  • AI大模型(六)Langchain核心模块与实战(一)
  • 使用LVM和扩展文件系统增加root分区存储容量
  • 信号和槽(4)
  • 3dmax物理材质转换标准材质,物理材质转VR材质,VR材质转标准材质3dmax物理材质转标准材质插件
  • 98.验证二叉搜索树