2

それはおそらく初心者の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;
}

基本的には問題なくコンパイルでき、問題なく接続でき、問題なくクエリを実行できますが、2回目にデータを取得しようとすると、ファイル「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;
}
4

2 に答える 2

5

passwordフィールドがデータベースのように定義されていると仮定すると、を使用して取得するvarcharことはできません。代わりに関数getString()を使用する必要があります。blobgetBlob()

ループは次のように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;
        }
    }
}

補足:コードには他にもいくつかの問題があることに注意してください。

  • ステートメント ハンドルを削除する必要があるため、(デストラクタではなく) 関数delete pstmt;内の適切な場所でa を実行する必要があります。(しかし、とにかくValidCredentials()その場合に準備済みステートメントを使用する理由は何ですかただし、準備されたステートメントの代わりに、準備されたステートメントは非常に使用率が高く、CPU を集中的に使用するクエリに最も役立つことに注意してください。準備済みステートメントの代わりに))
  • delete res同様に、デストラクタではなく、try ブロックの最後でResultSet を削除 ( ) する必要があります。
  • pstmtres、またはを使用する前に、必ず NULL をチェックしてくださいCon
  • stmt使用されていないようで、削除しないでください。
于 2013-04-05T16:42:44.630 に答える
0
  1. mysql c++ コネクタをダウンロードする
  2. mt または mtd を使用して mysqlcppconn-static プロジェクトをコンパイルします
  3. あなたのプロジェクトは CPPCONN_LIB_BUILD を追加します
  4. あなたのプロジェクトは、(2)ビルドされた静的ライブラリを追加します
于 2016-04-25T06:02:51.583 に答える