【问题标题】:Homemade vs. Java Serialization自制 vs. Java 序列化
【发布时间】:2008-10-28 19:22:08
【问题描述】:

我有某个 POJO 需要在数据库中持久化,当前设计将其字段指定为单个字符串列,并且向表中添加其他字段不是一种选择。

意思是,对象需要以某种方式序列化。因此,为了基本实现,我设计了自己的序列化形式的对象,这意味着将它的所有字段连接成一个漂亮的字符串,由我选择的分隔符分隔。但这相当难看,并且可能会导致问题,比如其中一个字段是否包含我的分隔符。

所以我尝试了基本的 Java 序列化,但从我进行的基本测试来看,这不知何故变成了一项非常昂贵的操作(构建一个 ByteArrayOutputStream、一个 ObjectOutputStream 等等,与反序列化相同)。

那么我有哪些选择?序列化对象以进入数据库的首选方式是什么?

编辑:这将是我项目中非常常见的操作,因此开销必须保持在最低限度,而性能至关重要。此外,第三方解决方案很好,但无关紧要(通常会产生我试图避免的开销)

【问题讨论】:

    标签: java database serialization


    【解决方案1】:

    Elliot Rusty Harold 写了一个nice argument 反对对他的 XOM 库中的对象使用 Java 对象序列化。同样的原则也适用于你。内置 Java 序列化是 Java 特定的、脆弱且速度慢,因此最好避免使用。

    您在使用基于字符串的格式方面的想法大致正确。正如您所说,问题在于您遇到了分隔符的格式/语法问题。解决方案是使用已经构建的格式来处理这个问题。如果这是一种标准化格式,那么您也可以使用其他库/语言来操作它。此外,基于字符串的格式意味着您有希望通过观察数据来理解它;二进制格式删除了该选项。

    XML 和 JSON 是这里的两个很好的选择;它们是标准化的、基于文本的、灵活的、可读的,并且有很多库支持。它们的性能也会出人意料地好(有时甚至比 Java 序列化更快)。

    【讨论】:

    • 我发现 XML 和 JSON 比 Java 序列化慢大约 5 倍。你有没有更快的例子。
    • 内置的 Java 序列化也是 JVM 特定的。不能以任何实际方式便携
    • 该链接中没有任何内容可以构成“不错的论点”,甚至是论点。只是一连串的废话,并不是所有的都是正确的。
    【解决方案2】:

    你可以试试Protocol Buffers,它是 Google 的一个开源项目,据说速度很快(生成比 XML 更短的序列化形式,并且运行速度更快)。它还可以轻柔地处理添加新字段(插入默认值)。

    【讨论】:

      【解决方案3】:

      您需要在解决方案中考虑版本控制。数据不兼容是任何涉及使用对象二进制序列化的解决方案都会遇到的问题。如何将较旧的数据行加载到较新版本的对象中?

      因此,上述涉及序列化为名称/值对的解决方案是您可能想要使用的方法。

      一种解决方案是包含版本号作为字段值之一。随着新字段的添加、修改或删除,可以修改版本。

      在反序列化数据时,您可以为每个版本使用不同的反序列化处理程序,这些处理程序可用于将数据从一个版本转换为另一个版本。

      【讨论】:

        【解决方案4】:

        XStreamYAMLOGNL 被认为是简单的序列化技术。 XML 一直是最常见的,但 OGNL 以最少的元数据提供了最大的灵活性。

        【讨论】:

          【解决方案5】:

          考虑将数据放入Properties 对象并使用其load()/store() 序列化。这是一种基于文本的技术,因此在数据库中仍然可以读取:

          public String getFieldsAsString() {
            Properties data = new Properties();
            data.setProperty( "foo", this.getFoo() );
            data.setProperty( "bar", this.getBar() );
            ...
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            data.store( out, "" );
            return new String( out.toByteArray(), "8859-1" );   //store() always uses this encoding
          }
          

          要从字符串加载,请使用新的Properties 对象和load() 数据执行类似操作。

          这比 Java 序列化更好,因为它可读性强且紧凑。

          如果您需要支持不同的数据类型(即不仅仅是字符串),请使用 BeanUtils 将每个字段转换为字符串表示。

          【讨论】:

          • Jason 感谢您的帮助,不幸的是,最后两个解决方案与此无关。你能详细说明第一个吗?
          【解决方案6】:

          如果您的 POJO 由字符串和原始类型组成,我想说您的初始方法并不是那么糟糕。您可以强制转义分隔符以防止损坏。此外,如果您使用 Hibernate,则将序列化封装在 custom type 中。

          如果您不介意其他依赖项,Hessian 应该是一种更有效的 Java 对象序列化方式。

          【讨论】:

            【解决方案7】:

            标准的JavaBeans持久化机制怎么样:

            java.beans.XMLEncoder
            java.beans.XMLDecoder
            

            它们能够从 XML(已持久化为 XML)创建 Java POJO。从记忆中,它看起来(有点)像......

            <object class="java.util.HashMap">
                <void method="put">
                    <string>Hello</string>
                    <float>1</float>
                </void>
            </object>
            

            您必须提供PersistenceDelegate 类,以便它知道如何持久化用户定义的类。假设您不删除任何公共方法,它对架构更改具有弹性。

            【讨论】:

              【解决方案8】:

              您可以通过外部化您的对象来优化序列化。这将使您完全控制它的序列化方式并提高流程的性能。这很简单,只要你的 POJO 简单(即没有对其他对象的引用),否则你很容易破坏序列化。

              tutorial here

              编辑:并不暗示这是首选方法,但如果 ti 对性能至关重要并且您只能在表中使用字符串列,那么您的选择将非常有限。

              【讨论】:

                【解决方案9】:

                如果您使用分隔符,则可以使用您知道在文本中永远不会出现的字符,例如 \0,或特殊符号 http://unicode.org/charts/symbols.html

                但是,将数据发送到数据库并将其持久化所花费的时间可能远大于序列化的成本。所以我建议从一些简单易读的东西开始(比如 XStream),然后看看你的应用程序在哪里花费了大部分时间并进行优化。

                【讨论】:

                  【解决方案10】:

                  我有某个 POJO 需要在数据库中持久化,当前设计将其字段指定为单个字符串列,并且向表中添加其他字段不是一种选择。

                  你能创建一个新表并将外键放入该列吗!?!? :) 我怀疑不是,但让我们覆盖所有的基础!

                  序列化: 我们最近进行了这个讨论,以便如果我们的应用程序崩溃,我们可以将它恢复到与以前相同的状态。本质上,我们将持久性事件分派到队列中,然后它会抓取对象,锁定它,然后将其序列化。这似乎很快。你要序列化多少数据?您可以使任何变量瞬态(即缓存变量)吗?你可以考虑拆分你的序列化吗? 当心:如果您的对象更改(锁定)或类更改(不同的序列化 id)会发生什么?您需要将所有已序列化的内容升级到最新的类。也许你只需要把它保存一夜就可以了?

                  XML: 你可以使用像 xstream 这样的东西来实现这一点。建立一些定制的东西是可行的(一个很好的面试问题!),但我自己可能不会这样做。何苦?请记住,如果您有循环链接,或者您是否多次引用对象。重建对象并不是那么简单。

                  数据库存储: 如果您使用 Oracle 10g 来存储 blob,请升级到最新版本,因为 c/blob 性能会大大提高。如果我们正在谈论大量数据,那么也许压缩输出流?

                  这是一个实时应用程序,还是会有一两秒钟的停顿,您可以安全地保存实际对象?如果你有时间,那么你可以克隆它,然后将克隆保存在另一个线程上。坚持到底是为了什么?在事务中完成是否重要?

                  【讨论】:

                    【解决方案11】:

                    考虑更改您的架构。即使您找到一种将 POJO 序列化为字符串的快速方法,您如何处理不同的版本?如何从 X->Y 迁移数据库?还是从 A->D 更糟?我看到我们将序列化对象存储到 BLOB 字段中并且必须跨多个版本迁移客户的问题。

                    【讨论】:

                      【解决方案12】:

                      你看过JAXB吗?它是一种机制,您可以通过它定义一套从 XML 模式创建的 java 对象。它允许您从对象层次结构编组到 XML 或将 XML 解组回对象层次结构。

                      【讨论】:

                        【解决方案13】:

                        我将第二个建议使用 JAXB,或者可能是 XStream(前者更快,后者更关注对象序列化部分)。 另外,我将进一步建议一个不错的基于 JSON 的替代方案,Jackson (http://jackson.codehaus.org/Tutorial),它可以将 bean 完全序列化/反序列化为 JSON 文本以存储在列中。

                        哦,我绝对同意在任何情况下都不要使用 Java 二进制序列化来进行长期数据存储。协议缓冲区也是如此;两者都太脆弱了(它们更适合紧密耦合系统之间的数据传输)。

                        【讨论】:

                          【解决方案14】:

                          你可以试试Preon。 Preon 的目标是二进制编码数据,就像 Hibernate 对关系数据库和 JAXB 对 XML 一样。

                          【讨论】:

                            猜你喜欢
                            • 2018-11-10
                            • 2012-06-21
                            • 2020-04-05
                            • 1970-01-01
                            • 2011-11-09
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多