c ++ boost :: archives和mySql BLOB,反序列化时出错

时间:2015-01-13 14:59:24

标签: c++ mysql serialization boost blob

我比较熟悉c ++,mysql和boost ......

我正在尝试使用BLOB将c ++对象存储在mySQL数据库中。

我正在使用boost :: archive来序列化和反序列化我的对象。

存储blob似乎工作正常,但是当我尝试反序列化结果blob时,我的程序崩溃了。 我真的会暗示如何使这项工作成功。

我的目标是存储更复杂的对象,但就目前而言,我正在尝试使用一个非常简单的类:

class user
{
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & id_;
        ar & name_;
        ar & age_;
    }
    int id_;        
    std::string name_;
    int age_;

public:
    user () {};  
    user (int id,std::string name, int age) 
    {
        id_ = id;
        name_ = name;
        age_ = age;

    };
    int id(){
        return id_;
    };
    std::string name(){
        return name_;
    };
    int age(){
        return age_;
    };
};

这是主要功能:

int main(){
    // a test object
    user u1(1,"myName",20);

    // serialization
    std::stringstream str;
    { 
        boost::archive::binary_oarchive oa(str);
        oa << u1;
    }

    //mysql
    sql::Driver *driver;
    sql::Connection *con;
    sql::Statement *stmt;
    sql::ResultSet *sqlRes;
    sql::PreparedStatement *prep_stmt;
    try {
        /* Create a connection */
        driver = get_driver_instance();
        con = driver->  connect("tcp://127.0.0.1:3306", "root", "mypass");
        stmt = con->createStatement();

        //test database with a table named users containing only one column, a BLOB(10000)
        stmt->execute("use test");

        prep_stmt = con -> prepareStatement ("insert into users(obj) VALUES(?)");
        prep_stmt->setBlob(1,&str);
        prep_stmt->execute();
    } 
    catch (sql::SQLException &e) {
        //some stuff...
        (...)
    }

    //Reading the only element in the table
    sqlRes = stmt->executeQuery("select * from users");
    sqlRes->next();
    std::istream *blobdata = sqlRes->getBlob(1);

    //trying to deserialize the blob...
    user newUser;
    {
        boost::archive::binary_iarchive ia(*blobdata); //crashes at this line
        ia >> newUser;
    }

    //If it worked, we should see our original user data...
    cout << "id = "<< newUser.id() <<endl;
    cout << "name = "<< newUser.name() <<endl;
    cout << "aeg = "<< newUser.age() <<endl;

    return 0;
}

我知道我可能做的事情非常糟糕,但我无法理解!

请帮帮我,谢谢。


编辑1:

getBlob()返回null_ptr,我不知道为什么。

如果我这样做而不是让对象回来:

std::stringstream ss;
ss << sqlRes->getString(1);

user newUser;
{
    boost::archive::binary_iarchive ia(ss); 
    ia >> newUser;
}

它工作正常并且对象被正确恢复......不确定它是否适用于更复杂的对象。


编辑2:

事实证明,在我的环境中出现了一些问题,因为@sehe(感谢你的帮助)尝试了我做的同样的事情并且对他有用。所以上面的原始代码实际上是正确的。

1 个答案:

答案 0 :(得分:1)

我刚刚花时间完全重播了这个例子。

它对我有用。我创建了这样一个数据库:

 create database test;
 use test;
 create table users (obj mediumblob NULL);

我编译以下程序(根据需要替换数据库用户/名称):

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <cppconn/driver.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/exception.h>
#include <sstream>
#include <iostream>

class user
{
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & id_;
        ar & name_;
        ar & age_;
    }
    int id_;        
    std::string name_;
    int age_;

public:
    user () {};  
    user (int id,std::string name, int age) 
    {
        id_ = id;
        name_ = name;
        age_ = age;

    };
    int id(){
        return id_;
    };
    std::string name(){
        return name_;
    };
    int age(){
        return age_;
    };
};

int main(){
    // a test object
    user u1(1,"myName",20);

    // serialization
    std::stringstream str;
    { 
        boost::archive::binary_oarchive oa(str);
        oa << u1;
    }

    //mysql
    sql::Driver *driver;
    sql::Connection *con;
    sql::Statement *stmt;
    sql::ResultSet *sqlRes;
    sql::PreparedStatement *prep_stmt;
    try {
        /* Create a connection */
        driver = get_driver_instance();
        con = driver->  connect("tcp://127.0.0.1:3306", "root", "*********");
        stmt = con->createStatement();

        //test database with a table named users containing only one column, a BLOB(10000)
        stmt->execute("use test");

        prep_stmt = con -> prepareStatement ("insert into users(obj) VALUES(?)");
        prep_stmt->setBlob(1,&str);
        prep_stmt->execute();
    } 
    catch (sql::SQLException &e) {
        //some stuff...
        exit(255);
    }

    //Reading the only element in the table
    sqlRes = stmt->executeQuery("select * from users");
    sqlRes->next();
    std::istream *blobdata = sqlRes->getBlob(1);

    //trying to deserialize the blob...
    user newUser;
    {
        boost::archive::binary_iarchive ia(*blobdata); //crashes at this line
        ia >> newUser;
    }

    //If it worked, we should see our original user data...
    std::cout << "id   = " << newUser.id()   << std::endl;
    std::cout << "name = " << newUser.name() << std::endl;
    std::cout << "aeg  = " << newUser.age()  << std::endl;

    return 0;
}

注意这会泄漏资源。你会想要解决这个问题。

运行时,会打印

sehe@desktop:/tmp$ ./test
id   = 1
name = myName
aeg  = 20

mysql显示:

mysql> select * from users;
+---------------------------------------------------------------------+
| obj                                                                 |
+---------------------------------------------------------------------+
|        serialization::archive
                                                   myName    |
+---------------------------------------------------------------------+
1 row in set (0.00 sec)