【问题标题】:MySQL C++ Connector crashes my app at ResultSet->getString()MySQL C++ 连接器在 ResultSet->getString() 处使我的应用程序崩溃
【发布时间】:2013-03-27 19:28:14
【问题描述】:

可能又是我在问菜鸟 C++ 问题

在使该死的(对不起语言)MySQL C++ 连接器工作时,我头疼不已。我不知道是写得不好还是什么,但根据我的经验,我从来没有遇到过这么多的麻烦。

无论如何,我让它连接并在连接/查询失败时抛出异常,这对我来说是一件大事:U:P。实际问题来自我获取查询结果。不管我做什么,我的应用程序总是崩溃:S

我使用了 32 位安装程序和来自 32 位 MySQL 服务器的 libmysql.dll/lib(因为我正在编译一个 32 位应用程序,所以我认为这是正确的做法)

这里有一些代码,你可以想象我在说什么

DBManager.h

#ifndef DBMANAGER_H
#define DBMANAGER_H
#define CPPCONN_PUBLIC_FUNC
#define CPPCONN_LIB_BUILD True

#include <string>
#include "mysql_connection.h"
#include "mysql_driver.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>

class DBManager
{
public:
    static DBManager* Instance();
    bool Query(const char* Query);
    void Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName);
    bool ValidCredentials(const char* Username, const char* Password);
    void ManageException(sql::SQLException &e);

    ~DBManager();

protected:
    static DBManager* pInstance;

private:
    DBManager() {};
    DBManager(DBManager const&){};
    DBManager& operator=(DBManager const&){};

    sql::mysql::MySQL_Driver* driver;
    sql::Connection *Con;
    sql::PreparedStatement *pstmt;
    sql::ResultSet *res;
    sql::Statement *stmt;

    bool isConnected;
};

#endif

现在是 cpp 文件 DBManager.cpp

#include "DBManager.h"

DBManager* DBManager::pInstance = NULL;

DBManager* DBManager::Instance()
{
    if (!pInstance)
    {
        pInstance = new DBManager();
    }

    return pInstance;
}

bool DBManager::Query(const char* Query)
{
    return true;
}

DBManager::~DBManager()
{   
    delete Con;
    delete pstmt;
    delete res;
    delete stmt;
}

void DBManager::ManageException(sql::SQLException& e)
{
    if (e.getErrorCode() != 0) {
        std::cout << "# ERR: SQLException in " << __FILE__;
        std::cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << std::endl;
        std::cout << "# ERR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl;
    }
}

void DBManager::Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName)
{
    try {
        driver = sql::mysql::get_mysql_driver_instance();
        std::string connDSN = "tcp://" + std::string(DbHost) + ":3306";

        Con = driver->connect(connDSN, sql::SQLString(DbUser), sql::SQLString(DbPass));
        Con->setSchema(sql::SQLString(DbName));
        isConnected = true;

        std::cout<<"Database connection successul."<<std::endl;

    } catch(sql::SQLException &e) {
        ManageException(e);
        isConnected = false;

        return;
    }
}

bool DBManager::ValidCredentials(const char* Username, const char* Password)
{
    bool cred = false;

    try {
        pstmt = Con->prepareStatement("SELECT * FROM account WHERE account_name=? LIMIT 1"); // Smart use of indexing
        pstmt->setString(1, Username);
        res = pstmt->executeQuery();

        while(res->next())
        {
            if (res->getString("password") == Password)
            {
                cred = true;
            }
        }
    }
    catch(sql::SQLException &e) {
        ManageException(e);
        return false;
    }

    return cred;
}

基本上,它编译没有问题,连接没有问题,执行查询没有问题,但是第二次我尝试检索数据时在文件“xutils.cpp”中抛出了一些断点异常。我真的不知道我做错了什么。我在编译调试时使用了 DEBUG 库。嗯 libmysql.dll 应该被释放,因为我从服务器包中提取了它,但我似乎没有找到它作为编译我自己的源。

我真的不知道为什么它会那样崩溃和燃烧:/

PS:不要介意密码的不散列,这对我来说实际上只是一个概念证明......首先让它工作,然后保护它:U

PS:我还在项目中编译并准备好 Boost 库,如果有帮助的话:U

编辑:主要功能

bool ServerRunning = true;
int main(int argc, char** argv)
{
    #ifdef _WIN32
        std::string title = TEXT("Window Title Change");
        SetConsoleTitle(title.c_str());
    #endif;

    std::cout<<"Loading Configuration File..."<<std::endl<<std::endl;

    std::string path = boost::filesystem::path(boost::filesystem::current_path()).string();
    path += "\\Config.ini";

    INIParser* Config = new INIParser(path.c_str()); //MinINI

    // Sockets data
    std::string listenIP = Config->GetString("Network", "ListenIP", "127.0.0.1");
    unsigned short listenPort = Config->GetInt("Network", "ListenPort", 5000);

    // Database data
    std::string dbHost = Config->GetString("Database", "Host", "localhost");
    std::string dbUser = Config->GetString("Database", "User", "root");
    std::string dbPass = Config->GetString("Database", "Password", "");
    std::string dbName = Config->GetString("Database", "Database", "authserv");
    unsigned short dbPort = Config->GetInt("Database", "Post", 1000);

    // General settings
    int sessionTimeout = Config->GetInt("Settings", "SessionTimeout", 10);
    int maxClients = Config->GetInt("Settings", "MaxClients", 10);
    int serverTimeout = Config->GetInt("Settings", "GameserverTimeout", 1);

     // Begin Initialization
     DBManager::Instance()->Connect(dbHost.c_str(), dbPort, dbUser.c_str(), dbPass.c_str(), dbName.c_str());
     bool loginSuccess = DBManager::Instance()->ValidCredentials("Username", "Password");

    char c;
    while (ServerRunning)
    {
        std::cin>>c;

        if (c == 'q')
        {
            ServerRunning = false;
        }
    }

    return 0;
}

【问题讨论】:

  • 我能看到那个异常吗?
  • 好吧,我在这里上传了图片img441.imageshack.us/img441/2415/mysqlcrash.jpg 希望对您有所帮助:U 这对我来说毫无意义,因为它是 x.x
  • 我在看这个......你也可以发布你的 main() 函数吗?注意:您可以想象不止一次分配您的语句,而不会在两者之间删除。
  • 用我的 main() 函数更新了底部的主帖
  • 数据库中password列是否定义为varchar

标签: c++ crash mysql-connector


【解决方案1】:
  1. 下载mysql c++连接器
  2. 编译mysqlcppconn-static项目使用mt或mtd
  3. 您的项目添加 CPPCONN_LIB_BUILD
  4. 您的项目添加 (2) 已构建的静态库

【讨论】:

    【解决方案2】:

    假设password字段在数据库中定义为varchar,你不能使用getString()来检索它。您必须改用blob 函数getBlob()

    这就是while 循环的样子:

    while(res->next())
    {
        std::istream * retrievedPassword_stream = res->getBlob("password");
        if (retrievedPassword_stream)
        {
            char pws[PASSWORD_LENGTH+1]; // PASSWORD_LENGTH defined elsewhere; or use other functions to retrieve it
            retrievedPassword_stream->getline(pws, PASSWORD_LENGTH);
            std::string retrievedPassword(pws); // also, should handle case where Password length > PASSWORD_LENGTH
            if (retrievedPassword == std::string(Password))
            {
                cred = true;
            }
        }
    }
    

    Side cmets:请注意,代码还有一些其他问题。

    • 必须删除语句句柄,因此您应该在ValidCredentials() 函数(而不是析构函数)的适当位置执行delete pstmt;。 (但是,为什么在这种情况下仍然使用准备好的语句?最好在构造函数(或调用查询的函数之外的其他地方)中初始化准备好的语句,以及在析构函数中删除或在其他地方,如果您确实使用准备好的语句。但是,请注意,准备好的语句对于非常高使用率和高 CPU 密集型的查询最有用,因此请使用它来验证密码在这里可能并不重要(您可以只执行常规查询,而不是准备好的语句)。)
    • 同样,需要在 try 块的末尾而不是在析构函数中删除 ResultSet (delete res)。
    • 在使用 pstmtresCon 之前,请务必检查 NULL。
    • stmt 似乎未使用,不应删除。

    【讨论】:

    • 呵呵,谢谢朋友的回答。希望我能为这个答案多次投票给你。我从来没有想过这是问题所在。你对我在这种情况下如何调试有什么建议吗?我真的不知道它的列类型的东西,我以为我用来编译的库有缺陷或者什么 x.x
    • MySQL 连接器的 C++ API 的文档非常稀少,正如您所见,因此在很大程度上必须在进行时弄清楚。在这种情况下,我设置了一个虚拟数据库来尝试模拟这个问题,同时我查看了可以在 ResultSet 对象res 上调用的所有可用函数(Visual Studio 的智能感知使这更容易)。当我注意到getBlob() 函数是一个选项时,我将二加二与人们通常为文本字符串创建的varchar 字段类型放在一起,然后尝试了。有效。我希望有一个魔术。
    猜你喜欢
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    相关资源
    最近更新 更多