在 C++ 中序列化对象并作为 blob 类型存储在 mysql 中

发布于 2024-08-31 07:11:28 字数 854 浏览 1 评论 0原文

我正在使用 mysql/C++ 连接器连接到 mysql 数据库。我有一些复杂的数据结构,所以我需要序列化它们并保存在数据库中。

我尝试了类似以下的内容。

vector<int> vectorTest(10,100);
istream *blob = NULL;
ostringstream os;
int size_data = sizeof(vector<int>);

blob = new istringstream((char*)&vectorTest, istringstream::in | istringstream::binary);
string qry = "INSERT INTO vector(id,object) VALUES (?,?)";

prep_stmt = con->prepareStatement(qry);

prep_stmt->setInt(1,1);
prep_stmt->setBlob(2,blob);
prep_stmt->execute();

我只是在这里尝试了一个小例子。然而,矢量对象没有被保存。

或者我可以使用以下方法。

ostringstream os;
int size_data = sizeof(vector<int>);
os.write((char*)&vectorTest, size_data);

但是我不知道如何将输出流重定向到输入流,因为 setBlob() 方法需要 istream 作为输入参数。

我可以知道如何让这些示例发挥作用吗?如果我的方法不正确,任何人都可以提供代码示例或改进给定的代码段吗?非常感谢您的立即回复。

谢谢

I am using mysql/C++ connector to connect to a mysql database. I have some complex data structures so I need to serialize those and save in the database.

I tried something like the following.

vector<int> vectorTest(10,100);
istream *blob = NULL;
ostringstream os;
int size_data = sizeof(vector<int>);

blob = new istringstream((char*)&vectorTest, istringstream::in | istringstream::binary);
string qry = "INSERT INTO vector(id,object) VALUES (?,?)";

prep_stmt = con->prepareStatement(qry);

prep_stmt->setInt(1,1);
prep_stmt->setBlob(2,blob);
prep_stmt->execute();

I just tried a small example here. However the vector object is not getting saved.

Alternatively can I can use the following approach.

ostringstream os;
int size_data = sizeof(vector<int>);
os.write((char*)&vectorTest, size_data);

However I don't know how to redirect the outputstream to an inputstream, because the setBlob() method needs an istream as the input parameter.

Can I know how to get any of this examples working ? If my approach is incorrect can anyone provide a code example or improve the given code segment ? Your immediate response is greatly appreciated.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

孤君无依 2024-09-07 07:11:28

你的处理方式完全错误。这不是“序列化”,事实上它很可能与序列化相反——它只是试图将向量的原始内存转储写入数据库。想象一下,向量看起来像这样:

struct vector_int {
  unsigned int num_elements;
  int* elements;
};

其中 elements 是一个动态分配的数组,用于保存向量的元素。

最终写入数据库的是 num_elements 的值,然后是指针 elements 的值。元素数据不会写入数据库,如果您要在程序的不同运行中将指针位置加载回向量中,则它指向的位置将包含垃圾。 std::vector 也会发生同样的事情,因为它包含动态分配的内存,在您的情况下,这些内存将作为指针值写出,而其他内部状态在重新加载时可能无效。

“序列化”的全部目的就是避免这种情况。序列化意味着将像这样的复杂对象转换为字节序列,其中包含重构原始对象所需的所有信息。您需要迭代向量并写出其中的每个整数。此外,您需要设计一种格式,当您读回它时,您可以确定一个整数的结束位置和下一个整数的开始位置。

例如,您可以用空格分隔整数,并像这样写出它们:

1413 1812 1 219 4884 -57 12 

然后,当您读回这个 blob 时,您必须将该字符串解析回七个单独的整数,并将它们插入到新创建的向量中。

要写出的示例代码:

vector<int> vectorTest(10,100);
ostringstream os;

for (vector<int>::const_iterator i = vectorTest.begin(); i != vectorTest.end(); ++i) 
{
  os << *i << " ";
}

// Then insert os.str() into the DB as your blob

要读入的示例代码:

// Say you have a blob string called "blob"

vector<int> vectorTest;
istringstream is(blob);
int n;

while(is >> n) {
  vectorTest.push_back(n);
}

现在,从空间角度来看,这不一定是最有效的方法,因为这会在将整数插入数据库之前将它们转换为字符串,这将比 if 占用更多的空间您刚刚将它们作为二进制编码的整数插入。但是,在这种情况下,写出和读入的代码会更加复杂,因为您必须关心如何将整数打包为字节序列以及如何将字节序列解析为一堆整数。上面的代码使用字符串,以便标准库流可以使这部分变得简单,并更直接地演示序列化的含义。

You're going about this completely the wrong way. This isn't "serialization", in fact it's quite possibly the opposite of serialization -- it's just trying to write out a raw memory dump of a vector into the database. Imagine for a second that vector looked like something this:

struct vector_int {
  unsigned int num_elements;
  int* elements;
};

Where elements is a dynamically allocated array that holds the elements of the vector.

What you would end up writing out to your database is the value of num_elements and then the value of the pointer elements. The element data would not be written to the database, and if you were to load the pointer location back into a vector on a different run of your program, the location it points to would contain garbage. The same sort of thing will happen with std::vector since it contains dynamically allocated memory that will will be written out as pointer values in your case, and other internal state that may not be valid if reloaded.

The whole point of "serialization" is to avoid this. Serialization means turning a complex object like this into a sequence of bytes that contains all of the information necessary to reconstitute the original object. You need to iterate through the vector and write out each integer that's in it. And moreover, you need to devise a format where, when you read it back in, you can determine where one integer ends and the next begins.

For example, you might whitespace-delimit the ints, and write them out like this:

1413 1812 1 219 4884 -57 12 

And then when you read this blob back in you would have to parse this string back into seven separate integers and insert them into a newly-created vector.

Example code to write out:

vector<int> vectorTest(10,100);
ostringstream os;

for (vector<int>::const_iterator i = vectorTest.begin(); i != vectorTest.end(); ++i) 
{
  os << *i << " ";
}

// Then insert os.str() into the DB as your blob

Example code to read in:

// Say you have a blob string called "blob"

vector<int> vectorTest;
istringstream is(blob);
int n;

while(is >> n) {
  vectorTest.push_back(n);
}

Now, this isn't necessarily the most efficient approach, space-wise, since this turns your integers into strings before inserting them into the database, which will take much more space than if you had just inserted them as binary-coded integers. However, the code to write out and read in would be more complex in that case because you would have to concern yourself with how you pack the integers into a byte sequence and how you parse a byte sequence into a bunch of ints. The code above uses strings so that the standard library streams can make this part easy and give a more straightforward demonstration of what serialization entails.

另类 2024-09-07 07:11:28

我写入 MySQL 数据库的解决方案是使用 Visitor 设计模式和抽象基类。我没有使用 BLOB 数据结构,而是使用字段(列):

struct Field
{
    // Every field has a name.
    virtual const std::string    get_field_name(void) = 0;

    // Every field value can be converted to a string (except Blobs)
    virtual const std::string    get_value_as_string(void) = 0;

    // {Optional} Every field knows it's SQL type.
    // This is used in creating the table.
    virtual unsigned int         get_sql_type(void) = 0;

    // {Optional} Every field has a length
    virtual size_t               get_field_length(void) = 0;
};

我构建了一个层次结构,包括数字、布尔值和字符串字段。给定 Field 指针或引用,可以生成 SQL INSERTSELECT 语句。

Record 将是字段的容器。只需为访问者提供一个 for_each() 方法:

struct Field_Functor
{
    virtual void    operator()(const Field& f) = 0;
};

struct Record
{
    void    for_each(Field_Functor& functor)
    {
      //...
      functor(field_container[i]);  // or something similar
    }
};

通过使用更真实的Visitor 设计模式,将 SQL 细节移至访问者中。访问者通过调用的方法知道字段属性。这会将 Field 结构简化为仅具有 get_field_nameget_value_as_string 方法。

struct Field_Integer;

struct Visitor_Base
{
    virtual void process(const Field_Integer& fi) = 0;
    virtual void process(const Field_String& fs) = 0;
    virtual void process(const Field_Double& fd) = 0;
};


struct Field_With_Visitor
{
    virtual void    accept_visitor(Visitor_Base& vb) = 0;
};

struct Field_Integer
{
    void    accept_visitor(Visitor_Base& vb)
    {
        vb.process(*this);
    }
};

The record using the `Visitor_Base`:
struct Record_Using_Visitor
{
    void accept_visitor(Visitor_Base& vistor)
    {
        Field_Container::iterator   iter;
        for (iter = m_fields.begin();
             iter != m_fields.end();
             ++iter)
        {
            (*iter)->accept_visitor(rv);
        }
        return;
    }
};

我当前的障碍是使用 MySQL C++ Connector 和 wxWidgets 处理 BLOB 字段。

您可能还想在下一个问题中添加标签:MySQLdatabase

My solution to writing to a MySQL database was to use the Visitor design pattern and an abstract base class. I did not use the BLOB data structure, instead used fields (columns):

struct Field
{
    // Every field has a name.
    virtual const std::string    get_field_name(void) = 0;

    // Every field value can be converted to a string (except Blobs)
    virtual const std::string    get_value_as_string(void) = 0;

    // {Optional} Every field knows it's SQL type.
    // This is used in creating the table.
    virtual unsigned int         get_sql_type(void) = 0;

    // {Optional} Every field has a length
    virtual size_t               get_field_length(void) = 0;
};

I built a hierarchy including fields for numbers, bool, and strings. Given a Field pointer or reference, an SQL INSERT and SELECT statement can be generated.

A Record would be a container of fields. Just provide a for_each() method with a visitor:

struct Field_Functor
{
    virtual void    operator()(const Field& f) = 0;
};

struct Record
{
    void    for_each(Field_Functor& functor)
    {
      //...
      functor(field_container[i]);  // or something similar
    }
};

By using a more true Visitor design pattern, the SQL specifics are moved into the visitor. The visitor knows the field attributes due to the method called. This reduces the Field structure to having only get_field_name and get_value_as_string methods.

struct Field_Integer;

struct Visitor_Base
{
    virtual void process(const Field_Integer& fi) = 0;
    virtual void process(const Field_String& fs) = 0;
    virtual void process(const Field_Double& fd) = 0;
};


struct Field_With_Visitor
{
    virtual void    accept_visitor(Visitor_Base& vb) = 0;
};

struct Field_Integer
{
    void    accept_visitor(Visitor_Base& vb)
    {
        vb.process(*this);
    }
};

The record using the `Visitor_Base`:
struct Record_Using_Visitor
{
    void accept_visitor(Visitor_Base& vistor)
    {
        Field_Container::iterator   iter;
        for (iter = m_fields.begin();
             iter != m_fields.end();
             ++iter)
        {
            (*iter)->accept_visitor(rv);
        }
        return;
    }
};

My current hurdle is handling BLOB fields with MySQL C++ Connector and wxWidgets.

You may also want to add the tags: MySQL and database to your next questions.

苄①跕圉湢 2024-09-07 07:11:28

boost 有一个序列化库(我从未使用过它)

或 XML 或 JSON

boost has a serialization library (I have never used it tho)

or XML or JSON

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文