在类似于db4o的对象数据库中处理数据维护

8

我一直觉得使用对象数据库(例如db4o)非常令人困惑的一点是,如何处理通常由SQL/PL-SQL处理的复杂迁移。

例如,假设您在关系型数据库中有一个名为my_users的表。最初,该表包含full_name列,现在在软件版本2中,您希望删除此列,在空格上拆分全名,并将第一个部分放入名为“first_name”的列中,将第二个部分放入名为“last_name”的列中。 在SQL中,我只需填充“first_name”和“second_name”列,然后删除名为“full_name”的原始列即可。

我该如何在db4o中实现这个功能?我需要编写一个Java程序来查找所有User.class的对象,将full_name设置为null,同时设置first_name和last_name吗?当我进行下一次svn提交时,将不再有与full_name对应的字段/bean属性,这会是一个问题吗?似乎在生产应用程序中使用它时,如果我的“模式”发生变化,我需要编写一个脚本来从版本x迁移数据到版本x+1,然后在版本x+2中实际上删除我要摆脱的版本x+1的属性,因为我无法编写Java脚本来修改不再属于我的类型的属性。
似乎问题的一部分在于关系型数据库管理系统(RDBMS)基于简单的大小写不敏感字符串名称解析所引用的对象,而在像Java这样的语言中,类型更加复杂,如果getter/setter/field不是运行时加载的类的成员,则无法引用属性,因此您需要在同一脚本中拥有两个版本的代码(嗯,自定义类加载器听起来很麻烦),将新版本的类存储在另一个包中(听起来很混乱),或者使用我提到的版本x+1 x+2策略(需要更多的规划)。也许从db4o文档中我没有发现明显的解决方案。

有什么想法吗?希望这有些意义。

2个回答

10

首先,db4o处理'简单' 场景,如自动添加或删除字段。当您添加字段时,所有现有对象都将存储默认值。当您删除字段时,现有对象的数据仍然存在于数据库中,您仍然可以访问它。重命名字段等是特殊的'refactoring'-调用

现在假设您的场景要做以下操作:

  1. 删除字段'full_name',添加新字段'first_name'和'second_name'
  2. 迭代所有'Address'对象
  3. 通过'StoredClass' API访问旧字段
  4. 分割、更改、更新等值。将新值设置在新字段上并存储对象。

假设我们有一个'Address'类。'full_name'字段已被删除。现在我们想将其复制到'firstname'和'surname'。然后,可以按如下方式进行(Java):

    ObjectSet<Address> addresses = db.query(Address.class);
    StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class);
    for (Address address : addresses) {
        String fullName = (String)metaInfoOfField.get(address);
        String[] splitName = fullName.split(" ");
        address.setFirstname(splitName[0]);
        address.setSurname(splitName[1]);
        db.store(address);
    }

正如您建议的那样,您需要为每个版本升级编写迁移代码。如果一个字段不再是您类的一部分,则必须像上面那样使用'StoredField'-API来访问它。
您可以使用ObjectContainer.ext().storedClasses()获取所有“存储”的类的列表。使用StoredClass.getStoredFields(),您可以获取所有存储字段的列表,无论该字段是否仍存在于您的类中。如果一个类不再存在,则仍然可以通过“GenericObject”类获取对象并访问它。
更新:对于需要在多个版本步骤中迁移数据库的复杂情况。
例如,在版本v3中,地址对象看起来完全不同。因此,v1到v2的“迁移脚本”不再具有它所需的字段(例如我的示例中的firstname和surename)。我认为有多种处理此问题的可能性。
假设这个想法是基于Java的,当然在.NET中也有相应的东西。你可以将迁移步骤设置为Groovy脚本。这样每个脚本就不会互相干扰。然后你可以在脚本中定义所需的类,以便每个迁移都有自己的迁移类。通过使用别名,你可以将你的Groovy迁移类与实际的Java类绑定起来。
对于复杂的场景,创建重构类。同样使用别名将这些类与其他类绑定。

2

我这里说的可能有点冒险,因为我没有太多重构数据的经验。

你做了一个奇怪的比较:如果你想要“热迁移”数据库,你可能需要像你描述的那样进行x+1x+2版本控制,但我不是一个数据库专家,所以也不知道如何用SQL实现这个功能。

然而,如果你是在“冷迁移”,你可以通过从旧数据实例化一个新对象,在存储新对象后删除存储中每个对象的旧对象来一步完成。参见db4o参考

但是,老实说:在关系型数据库中进行相同的过程也很复杂,因为你将不得不停用约束检查(和可能的触发器等)才能实际执行操作——也许不是在你提供的示例中,但对于大多数真实情况都是如此。毕竟,字符串拆分是如此简单,以至于几乎没有什么收获。

在SQL中,我只需填写“first_name”和“second_name”列

是的,通过简单的字符串拆分操作,你可以简单地完成这个任务。但在典型的重构场景中,你需要基于大量和复杂的规则来重组对象,这些规则可能不容易用SQL表达,可能需要复杂的计算或外部数据源。

为了做到这一点,你也必须编写代码。

毕竟,我认为这两个过程没有太大区别。你总是要小心处理活动数据,并且无论如何都会进行备份。重构很有趣,但持久性很棘手,因此在任何情况下同步它都是一个挑战。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接