教授告诉我们将序列化的Java对象存储为Blob,而不是定义关系表


21

我的教授告诉我们我们可以将对象映射到ID,而不是实际定义具有正确属性的表:

id (int)  |   Serialized Object (blob)
   1               10010110110

我可以看到很多问题。数据冗余,必须分别跟踪ID,必须将整个表放入内存中以搜索任何内容,并且**如果要更改Java代码中的模型,我将不再能够反序列化存储在数据库放入该模型。

我要么永远呆在那个模型上,要么我不得不做一些其他非常丑陋的事情来更改我的模型。**这一切对我来说似乎是不好的形式。我不同意我的教授吗?这样做有没有想到的好处?如果我是正确的话,我应该对我的教授说些什么吗?他正在向全班讲道,甚至说他以这种方式建立了项目。第二个意见将是伟大的。

该课程名为软件设计

我的教授没有说这是最好的方法,但他确实说这是定义关系表的合理选择。

该模型绝不是动态的。


评论不作进一步讨论;此对话已转移至聊天
保罗·怀特说GoFundMonica

Answers:


34
  1. 就其本身而言,这并不是一件坏事-一点也不。在没有适当背景(确切要求)的情况下争论“哪个更好”是徒劳的。

  2. 粗体部分是错误的。您可以轻松扩展已经序列化的对象以添加新字段,并实现与旧对象的完全二进制兼容性。您也可以简单地创建新类,而不用更改原始类。

您与教授的讨论应侧重于在不同情况下“关系”与“键值存储”的优缺点,而不是抽象的“更好”。或者,您也可以讨论圣诞节是否优于感恩节。

-阅读其他答案后进行编辑。

其他答案之一甚至是指出“很难想象一个优点胜过缺点的情况”。

因为整个讨论都必须针对具体问题(否则我们甚至不能定义“更好”和“更糟”),所以让我举一个具体的例子。它已经完全组成,但是我尝试充实尽可能多的细节。

想象一下,您有一个在线游戏站点,其中有一个数据库,该数据库存储不同在线游戏中玩家的统计信息(在浏览器中玩,用GWT编写,并交叉编译为javascript)。有些游戏是战略游戏,有些是动作游戏,有些是平台游戏。该数据库是关系数据库,存储球员,比赛历史和得分。

有一天,您会收到另一项要求:让玩家在游戏过程中将游戏状态保存到云中,以便他们稍后可以在同一点重新开始游戏。不用说,存储此临时状态的唯一原因是要返回游戏,该状态本身永远不会被自省。

现在,您有两个基本选择:

  • 由于游戏是用Java编写的,因此您可以轻松地获取模型,将其发送到服务器,以一行代码对其进行序列化并存储为Blob。该表将称为“ saved_games”,它将具有指向玩家的外键,依此类推。从数据库的角度来看,“保存游戏”是不透明的,不可分割的斑点。

  • 您可以为100个游戏中的每个游戏创建一个单独的关系模型(每个游戏将有数十张桌子)。例如,仅对于吃豆人,您将必须有一个表,用于存储所有未食用的颗粒,奖金,位置和鬼的当前状态的位置。如果某天某人甚至稍微修改了游戏,您将必须更新关系模型。同样,对于每种类型的游戏,您都必须实现一种逻辑,以将Java模型写入数据库,然后将其读回。

贾斯汀·凯夫(Justin Cave)的回答是,您应该选择第二种选择。我认为这将是一个巨大的错误。

另外,我有一种预感,贾斯汀·凯夫(Justin Cave)的看法是,我在上文中介绍的是“边缘”或“罕见”案件。我相信,除非他能提供某种硬数据(基于对世界上所有IT项目的代表性抽样,而不仅仅是美国的企业应用程序),否则我将认为这种观点是预测的经典案例。偏压。

实际上,在关系数据库中序列化Java对象的问题比看起来要深得多。它触及1NF的核心,即 属性的范围是什么?。如果您真的对该主题感兴趣,那么CJ Date会在他的数据库日期:写作2000-2006中发表一篇很棒的文章。


评论不作进一步讨论;此对话已转移至聊天
保罗·怀特说GoFundMonica

22

人们可以(也可以)成功交付完成此类任务的项目吗?不幸的是,是的,他们经常这样做。

这是一个好方法吗?不,这不对。基本上,您是在使用相对昂贵的数据库并将其变成相对较慢的文件系统。如果您真的想构建一个通过序列化和反序列化对象来保存其状态的系统,则最好使用文件系统而不是数据库。

如果您通过将对象序列化到数据库中来构建存储数据的系统,则不会与DBA成为朋友。您最终将存储冗余数据。您最终将获得非常不一致的数据-每当更新共享数据时,某些对象将最终使用新值,而某些对象将最终使用旧值。您将无法对数据进行任何形式的报告-任何人想要对数据进行的所有操作都将需要有人编写其他代码。在大多数企业中,这是一个巨大,巨大的问题,因为他们想要做一些事情,例如从一个系统中提取数据以加载到另一个系统中,或者拥有一个可以从多个前端应用程序中提供报告的报告系统。另外,正如您所指出的那样,当您

这种方法是否有优势?我猜您可以争辩说,实现该应用程序的第一个版本非常容易。而且,它使开发人员可以完全忽略与数据库正确交互相关的所有内容。我很难想象在许多情况下这些优势胜过该方法的诸多弊端。

至于您应该如何与这位特定的教授打交道,那是一个单独的问题(这个问题可能不在本论坛讨论范围之内)。如果您的教授正在积极地开发现实世界中的项目,那么他可能不会完全接受学生提出的关于他的方法从根本上是错误的论点(即使该方法确实从根本上是错误的)。您可以按照教授希望的方式来完成您的项目,并学习自行保存数据的正确方法(或在另一门课程中)。


2
你说了什么,再加上我的两分钱。可重用性与模块化和共享有关。对象模型专注于共享对象和重用代码。数据库模型专注于共享和重用数据。两种模式都不是完全和谐的。两种模式都不完美。调和这两者非常非常困难。
Walter Mitty 2014年

1
我同意这一点,但是我不希望看到一位教授教些什么,并且说这是一种更好的方式,而无需面对它。认为这是正确方法的所有其他贫困学生又如何进入现实世界呢?
凯文

当然。这种表述等于假装为数据的对象。它们是数据,但不是非常有用的数据。
Walter Mitty 2014年

要发布应用程序的第2版时,优势几乎总是消失了。
安迪

10

在某些情况下,这种设计很明智,而您没有描述项目的含义以及如何使用它,很难说这是否合适。

如果存储BLOB,您的DBA可能会讨厌您,但是在许多情况下,唯一的替代方法是将表转换为Entity-attribute-value,这会使DBA更加讨厌。另一种选择是使用非关系数据库,通常是基于对象的数据库或基于字典的数据库,或者是面向文档的数据库,某些DBA,尤其是那些只知道关系的DBA会更讨厌。非关系数据库有其自身的问题要解决,使用对象数据库存储对象肯定可以解决在关系系统中可以轻松解决的其他问题。

这样做有没有想到的好处?

存储序列化对象意味着您可以存储无模式数据(请注意,尽管有名称,无模式通常并不意味着实际上根本没有模式,而是只有隐式模式)。在许多问题域中,您可能无法在开发时提前定义架构,而遵循传统的关系数据库设计将意味着您必须每隔一周更改一次数据库的架构,或者最终得到一个包含以下内容的表: 80%的列中有80%的时间未使用,或者有数百个不同的表用于存储真正相同的数据,但没有一个表表明设计良好。此问题的根源通常是因为您正在将非关系问题域强制拟合到关系数据库中。

当然,在许多项目中,人们认为他们需要使用EAV,无模式或Blob存储,这些不必要地导致了原本可以避免的痛苦。您绝对应该与您的教授讨论他的推理是什么,并提供自己的论点。听取论点,并准备好您可能最终同意他,或者不同意,也许他错了。


7

我之前已经做过这-它在某些情况下的有用技术取决于所使用的序列化格式。如果这样做,请确保使用序列化格式,以使我可以反序列化模型的旧版本(例如XML)。

我通常会在数据格式导致复杂的关系模型而没有优势的情况下使用此方法(例如,当业务需求不需要任何过滤等时...)并且我已经在使用数据库(用于其他关系数据)。一个这样的情况是一个有用户查询的应用程序-关系模型有几个表来存储条件,嵌套条件(OR / AND等...),排序选项等……这非常复杂,因此当我们需要添加一个新功能,该功能需要对数据库进行更改,我用一个查询表替换了全部内容,并使用了表示所有其他选项的序列化Blob。

另一个案例是处理各种“工作”的系统。有几种不同类型的作业,每个作业都有不同的参数,没有业务要求就能基于这些参数搜索/过滤作业。将其存储为关系数据库将需要为每个作业类型至少创建1个新表,从而很难添加新的作业类型。而是将参数作为Blob存储在数据库中-每个作业类型负责序列化和反序列化其自身的参数。

通常,您会遇到类似这样的情况,但是不时出现上述情况,串行化Blob数据可以节省您的工作量,使您的应用程序更易于维护,并且没有真正的缺点。


6

贾斯汀·凯夫(Justin Cave)正确地认为这会导致冗余数据,但这实际上取决于您如何设计数据库。

将整个对象序列化为Blob的方法并不像大多数人认为的那样令人毛骨悚然。实际上,对于某些应用程序,这可能是您可以做的最好的设计,正如我在此处解释的那样:https : //stackoverflow.com/a/12644223/1121352

实际上,序列化对象至少会带来两个好处:

1- 减少阻抗不匹配:某些Java类型在SQL中是不可用的,特别是如果您使用大量的类和自定义类型,则从Java对象到SQL的来回转换可能会很麻烦,甚至会导致歧义。

2- 模式的灵活性更高。确实,关系模式对于共享相同结构的数据确实非常有用,但是如果一个类中的某些对象根据运行时的条件而具有不同的属性,则关系模式会极大地阻碍您的工作流程。

因此,这种方法肯定有好处(至少有这两种,但我肯定没有提到其他优点),但是当然要付出的巨大代价是您几乎失去了所有关系模式的好处。

但是,如果您精心设计数据库,则可以兼得两全:您仍然可以通过使用每个对象唯一的属性来设置关系模式(即,唯一键列),然后将该对象存储在Blob中。这样,您仍然可以在给定由对象属性定义的唯一标识符的情况下,确保快速检索对象,同时减少冗余,同时消除阻抗不匹配并保持Java对象的完全灵活性。

附带说明一下,一些数据库制造商曾尝试将关系模型和对象模型混合在一起,例如PostSQL和PostgreSQL中的JSON数据类型,以便您可以像处理任何关系列一样直接处理JSON,以及SQL3和OQL(对象查询语言)以向SQL添加(有限)对象支持。

最后,这都是设计问题,关系模型和对象模型之间必须折衷。

阅读注释后的/ EDIT:当然,如果您的数据必须可搜索(“可查询”),则不应将数据存储为Blob。但是,如果您的数据的某些部分不是可搜索的,而是某种元数据,那么将该数据部分作为对象存储在Blob中可能是一个很好的解决方案,尤其是如果该元数据具有灵活的结构并且可以随对象而变化。


5

让我们举一个实际的例子,说明我过去何时进行此操作。

我们有一个数据库,其中包含多用户应用程序的所有数据。该数据库还具有一个具有访问权限的用户表。所有这些数据均按预期进行了归一化。

然后,我们要求应用程序记住用户打开了哪些窗口以及他们在做什么,以便它可以在用户第二天早上开始工作时恢复其状态。

  • 首先,如果有时失败了,那不是偶然的吗

    • 例如,如果某人第一次使用该应用程序的新版本,它将忘记他们打开的窗口,那么……
  • 因此,如果对象发生更改,则会有100%的后备,因此我们无法读取该代码块。

  • 我们已经有一个具有访问控制,备份等功能的集中式数据库。
  • 将数据存储在文件中的成本很高,因为必须将文件放在所有用户计算机都可以访问的某种文件服务器上,或者必须编写API才能读取这些文件。

还有一次,我们有一个应用程序,它执行了许多长时间运行的计算,并且用户希望能够在断电等情况下从最后一次知道的好点重新开始计算。等等。可以预期应用程序将重新开始计算,并且由于有许多对象需要保存,因此规范化数据将非常昂贵。

由于数据库已经存在并且已用于定义良好的规范化应用程序数据,并且没有真正的理由不使用它来存储博客,因此我们选择了明智而快速的选择。


4

一个非常重要的因素:Java序列化(通过实现启用了序列化Serializable)本身就是一种非常糟糕的格式,因此您不应该真正将其用于永久对象存储。

Java序列化的缺点包括:

  • 数据不能真正从其他语言读取。
  • 维护序列化对象的前向兼容性不是一件容易的事,也就是说,如果向类中添加(或删除)字段,那么读取由早期版本的类创建的对象就不那么容易了。
  • 速度不是很快(但是您的里程可能会有所不同)

因此,如果您使用任何其他序列化格式,则会得到一个不错的键值存储,如果您使用Java序列化,则会一团糟。


答案中的事实完全是错误的:1)格式已包含详尽的说明;2)添加字段根本不是问题,格式非常灵活;3)速度取决于实际数据,但与JSON或XML等格式相当(有时更快,有时更慢)。基本上,整个答案是错误的,只不过一行:“其他语言无法真正读取数据”。
fdreger 2014年

1
除了1)错误的答案外,其余答案都是IMO有效的。如果你想有超过deserialisaton控制-当你添加这是需要/删除字段(特别是其最后的字段时)的界面显得笨重,而你需要覆盖更多的方法这里有必要readObjectreadReplace(最终场)。
jb。

您错了,添加和删除字段不需要编写任何方法。至于最后的字段-您的原始答案根本没有提到它们,如果确实如此,那将是无关紧要的(问题对于所有其他格式都是常见的)。最后,说“不是那么快(但您的里程可能会有所不同)”根本没有任何意义。您只有一个事实正确:关于其他语言的事实。这是称某事“一团糟”的非常薄弱的​​基础。
fdreger 2014年

1
添加字段不需要您编写任何方法,但是如果您想影响它们反序列化的方式,则需要指定该行为。我将尝试挖掘一些有关对象模型反序列化问题的参考。
jb。

3

这是一个有趣的主题,提供了一些经过深思熟虑的答案。我不熟悉存储和检索序列化对象的所有含义,我认为提供我可能会给DBA团队或开发团队的答案会很有趣:

关键是要满足当前和将来的要求,并保持解决方案尽可能简单,以最大程度地减少将来的支持工作。功能要求和非功能要求(例如,基础结构和数据库)都必须满足。记住80/20规则。了解App对业务的重要性以及适当的开发工作。

如果没有问题,请不要挂在数据库的空间,速度和内存上。

如果DBMS在批准的列表中,则只要成本合适,就可以在解决方案中使用它。使用关系数据库存储简单的Blob毫无问题,尤其是在这简化了事情的情况下。

如果解决方案是原型或早期阶段/版本,则在保持简单性上要施加更大的压力。只要您为数据模式进行规划,就可以始终在以后扩展它。

请记住,除非架构覆盖一个独立的业务区域并且业务规则严格,否则关系数据库不会强制执行完整性或一致性。(例如,序列化对象问题的解决方案可以考虑使用字典/本体样式存储库来实施规则)。

值得考虑的是,所有关系数据库都不使用纯粹的关系数据库架构(例如,星号,空间,非关系..),应用程序也可以将关系数据库用作非关系存储,如本问题所述。许多核心业务数据库都以这种方式工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.