Erlo

Qt个人项目总结 —— MySQL数据库查询与断言

2025-03-07 19:30:41 发布   14 浏览  
页面报错/反馈
收藏 点赞

个人Qt项目总结——数据库查询断言问题


  • 问题:

    • 当我使用MySQL数据库的查询操作时,
    • 如果查询的数据在数据库中不存在,那么Qt会直接被干崩溃
    • 但是?为什么呢?不应该是返回if语句中的结果吗,为什么会崩溃呢?
    • img
  • bug代码示例
    ===========================================================================================
            // 查询数据库获取哈希密码和盐
            QSqlQuery query(p->db);
            query.prepare("SELECT passwd, salt FROM musicplayer WHERE username = :username");
            query.bindValue(":username", username);
    
            if (!query.exec() || !query.next())
            {
                qDebug() db.lastError();
                QMessageBox::warning(this, "警告", "用户名或密码错误!");
                return;
            }
    ===========================================================================================
    

  • 为此,我特意写了一个函数用来测试这个问题

  • 但是,在此之前,先来回顾几个知识点

  • 1.query.exec()

    • query.exec() 用于执行 SQL 查询语句,返回值代表查询是否成功
    • 如果查询执行成功,返回true
    • 如果执行失败(例如表不存在、语法错误等),query.exec() 会返回 false
  • 2.query.next()

    • query.next() 用于获取查询结果的下一条数据,返回值代表下一行数据是否存在
    • 如果查询执行成功,返回true
    • 如果查询为空(没有任何匹配结果),query.next() 会返回 false
  • 3.与运算符||

    • 执行顺序是从左至右的

  • 现在再来看看测试函数

  • // 断言bug测试
    // 假设数据库已经连接
    void Widget::AssertTest()
    {
        QSqlQuery query(db);
    
    #if 1
        // 1.使用断言查询一个不存在的人(给Qt干崩溃了) —— 预处理语句
        // 查询结果为空时, query.next() 返回 false
        // 但是没有进一步操作无效数据,程序就跳转到错误处理部分
        // 然后,嘭!你的QT崩溃了,开始今天晚上的修bug之旅吧
    
        QString username = "111";
        query.prepare("select passwd, salt from musicplayer where username = :username");
        query.bindValue(":username", username);
    #else
        // 2.不使用断言查询一个不存在的人(Qt没有崩溃)	—— 拼接字符串
        // 查询结果为空时, query.next() 返回 false
        // 但是没有进一步操作无效数据,程序就跳转到错误处理部分
        // 会继续if条件分支,执行错误处理并退出
        // 没有进一步访问无效数据或发生未定义行为
        query.prepare("select passwd, salt from musicplayer where username = qwwq");
    #endif
    
        // 使用断言时,如果查询数据在数据库中不存在(exec执行),那么Qt就会崩溃
        // 但是如果将query.exec()和query.next()的执行顺序对调
        // 先执行query.next()再执行query.exec()呢
        // 如果这样做了,请尽量不要在你老师面前提及到这件事(会被揍的)........
        // 当然,如果有仇的话,出门的时候可以多报一下你老师的名字.......
    
        // || 的运算顺序是从左至右
    
        // 1.if (!query.exec() || !query.next())
        // 先执行query.exec(),再执行query.next()
        // 即:先确保查询语句是否成功再查询有效数据
    
        // 2.if (!query.next() || !query.exec())
        // 先执行query.next(),再执行query.exec()
        // 即:query.next()先执行,query.next()的行为就会是不可预测的(Qt说不定就又被干崩溃了),
        //     即使查询没有执行成功,通常也会返回false
    
        // 如果查询没有执行("exec()"),
        // query.next() 会试图访问无效的结果集,这可能会导致不可预料的行为,甚至崩溃
        // query.exec() 没有执行,那么query.next() 根本就不应该被执行,因为查询结果集并不存在
        // 调用 next() 就是访问不存在的数据
    
        // 人话:exec()是执行,next()是访问下一行数据
        // 你都没有执行,怎么可以访问下一行数据
        // 再说直接一点,你进家门,门都还没有打开,你就想躺平怎么可能嘛
    
        // 1.正确写法
        // if (!query.exec() || !query.next())
        // 2.错误写法
        if (!query.next() || !query.exec())
        {
            qDebug() 
  • 那么,问题来了,为什么使用断言Qt会崩溃,不使用断言就不会崩溃呢?

  • 这就得提到断言的工作原理了


  • 断言的工作原理

    • 断言是在开发过程中用来检查代码正确性的一种手段

    • 它会检查某个条件是否为真,如果条件为假,就会中断程序的执行,通常会抛出一个错误或崩溃

    • 断言的使用是根据编译模式的不同来决定的:

      • 在 调试模式 下,断言会被启用,而在 发布模式 下,它通常会被禁用

  • 为什么不使用断言就不会崩溃?

  • 因为query.next()query.exec()并不会使Qt崩溃,说白了就是断言的锅

  • Qt的设计并不要求开发者强制使用断言来检查查询结果的有效性

  • 当查询没有结果时,query.next() 返回 false,但不会抛出异常或触发断言

  • 它的行为是让开发者检查查询是否成功(通过 query.exec())以及是否有数据返回(通过 query.next()

  • 如果查询失败或没有结果,开发者通常会自己决定如何处理

  • 如果在没有结果的情况下继续访问数据,query.value() 会返回一个无效的默认值(例如空字符串),而不会触发崩溃


你以为就这样结束了吗,这个问题?作为bug的专业制造机,我怎么可能只生产一个bug?
还有一个强制性的DLC扩展包

提问:上面的代码还有一个bug,是什么呢?

    // 错误的断言方式(语法错误)
    // QString sql = "SELECT passwd, salt FROM musicplayer WHERE username = " + username;
    // 查询数据库获取哈希密码和盐
    QString sql = "SELECT passwd, salt FROM musicplayer WHERE username = '" + username + "'";
    QSqlQuery query(p->db);

不是,谁教你sql执行语句是这样写的啊,字符串格式怎么写的啊,用单引号括起来啊喂
是我自己写的啊,那没事了

  • 为什么不能这样写?
  • 假设我现在在查询用户名 zzz
  • 代码直接拼接 username,导致生成的 SQL 语句将 zzz 视为列名或标识符,而非字符串值
  • 如果数据库中不存在名为 zzz 的列,查询会返回空结果
  • 当用户名为 zzz 时,生成的 SQL 语法错误,导致查询失败或返回空结果
  • 若用户名包含空格或特殊字符(如 John Doe),问题会更明显,可能导致 SQL 语法错误

省流:语法错误 那你讲这么一大堆干什么啊喂


看了一下我以前写的项目总结,我只能说
不愧是我,bug制造者,调试的克星,代码的混乱之源,咖啡的吞噬者,深夜的守护者以及键盘毁灭者 —— 某苦逼大学生是也(借用美剧《权力的游戏》龙妈头衔梗)

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认