要删除还是要软删除,这是一个问题!


软删除是一种广泛应用于业务应用程序的模式。它允许您将某些记录标记为已删除,而无需从数据库中实际删除。有效地,可以防止选择软删除的记录,同时,所有旧记录仍可以引用该记录

什么时候使用软删除有意义? 如果您随机询问一些开发人员,则很可能您会听说软删除用于恢复已删除的记录。但是,如果这是唯一促使您集成软删除的业务需求,请三思而后行。在决定在项目中使用软删除之前,除了“简单数据还原”之外,还请考虑以下要求:

  1. 历史跟踪和审核(例如出于法律原因)
  2. 保持参考完整性,避免级联删除
  3. 您需要“优美”删除。例如,长时间运行的业务流程可能需要“删除”但仍然需要此数据才能完成的特定流程 如果您发现自己的业务要求与上面的列表匹配,则意味着您可能需要在应用程序中实现“软删除”功能。

实现软删除很容易!您只需将“ Is_Deleted”或“ Delete_Date”列添加到表(或文档的属性)中,并替换应用程序代码中的所有delete语句调用即可进行更新。是的,您需要修改所有检索语句以考虑此新属性。还是创建视图更好?还是物化视图?在这种情况下,我们可能需要实现“代替”触发器或存储过程API来处理视图。通过删除实体,您可能希望删除其引用的某些属性。在这种情况下,为了能够还原,还需要存储删除上下文。而且……这就是开发人员的生活变得复杂的地方。

软删除的挑战 实际上,实现“适当的”软删除并非易事。有时,开发人员选择不实施软删除,只是因为这需要很多工作。您可能会想到其他选项,例如带有特殊“垃圾箱”表的表镜像,该表包含“原始”表中的已删除记录。

但是,如果决定继续执行软删除实现,则需要考虑一些条件。

数据库支持。标记为已删除的记录的问题之一是它们的唯一键。举例来说-我们需要将用户及其电子邮件存储在一起。电子邮件必须是唯一的,因此,我们需要为存储用户的表创建唯一的索引。如果删除了一个用户,我们应该可以使用相同的电子邮件插入一个新用户。因此,您的数据库应该能够处理此类情况。选项之一-在唯一键中包含一个软删除标记字段。如果您的标记字段不是简单的布尔值,而是删除时间戳,则可以解决问题。

另一个选择-特殊的唯一索引。例如,在PostgreSQL中,它被称为部分唯一索引,在MSSQL过滤的索引中,它被称为。它们允许您通过指定谓词在构建索引时不考虑某些行。因此,对于软删除功能实现,我们可以从索引中排除“已删除”记录。

如果数据库支持视图触发器,则很有可能可以使用视图和instead of触发器类型创建数据模型。但是这种方法会影响性能,并且无法通过对基础表应用唯一约束来解决此问题。

应用支持。确保所有提及软删除实体的查询都经过仔细检查,否则可能导致意外的数据泄漏和严重的性能问题。在理想情况下,开发人员不应意识到软删除的存在。因此,如果可能,请尝试引入您的数据访问API,并防止开发人员使用其他工具来访问数据库(例如直接JDBC连接)。您甚至可能要覆盖标准的API,例如JPA的Entity Manager,以正确支持软删除。

重新使用标准API。首先,忘记使用某些标准的DB和JPA功能。如果您已经精心设计和调整了数据库表和约束模型以及JPA层,那么引入软删除要求您考虑以下事项:

  1. 标准级联策略将不起作用。请记住,在进行软删除的情况下,您不会删除记录,而是对其进行更新。如果您仍然需要级联删除,触发器可以帮助您实现此行为。
  2. 至于触发器-您也需要对其进行检查,以确保删除前和删除后触发器中的代码在更新为软删除期间在更新前的触发器中执行,而在“常见”更新过程。
  3. JPA生命周期回调@PreRemove和@PostRemove将无法正常工作。同样,寻找其他选项来实现这些回调中编码的功能。这里的规则类似于应用于触发器的规则-在与更新相关的回调中,您需要区分更新和软删除过程。 您仍然需要满足法规要求。例如-GDPR。该法规规定,如果用户需要,必须将其完全删除。为此,除了软删除之外,您还需要执行“清除”过程。在大多数情况下,此清除过程会影响数据库中的相关数据。因此,您需要小心,不要删除关键业务数据。

CUBA平台中的软删除实施 CUBA平台支持开箱即用的软删除功能,并提供软删除功能,作为默认应用程序行为的一部分。在大多数情况下,开发人员不必担心是否使用软删除。CUBA中的数据操作API与众所周知的JPA API相同,为99%。你,作为一个开发者,可以使用EntityManager的remove()甚至是随心所欲的使用JPQL来处理应用程序中的数据。

在后台,CUBA平台拦截对EntityManager和JPQL查询的所有调用,并根据应用程序设置转换它们。该框架将承担繁重的工作,并提供正确的应用程序行为:“已删除”记录将不受更新影响,DELETE语句将转换为UPDATE并且SELECT不会获取“已删除”数据。

该实现基于三个主要支柱:

  1. SoftDelete界面。CUBA使用JPA(EclipseLink)作为访问数据的默认框架。如果您的JPA实体实现了“ SoftDelete”接口,则CUBA不会从数据库中删除数据,而只是将其标记为已删除。
  2. EntityManager班级。这是处理CUBA中数据的主要API。它拦截对数据库的所有请求,并根据实体类型及其“软删除”字段值(启用或禁用)来调用deleteupdate语句。因此,如果需要,您可以在运行时禁用实体的软删除。尽管在CUBA平台的深处生成了一条更新语句,但这种方法使我们能够调用与实体删除相关的JPA实体回调。
  3. JoinExpressionProvider框架核心中的API接口。该SoftDeleteJoinExpressionProvider实现生成一个谓词,以考虑实体状态(已删除或未删除)及其在查询中的位置。例如,如果我们选择引用“软删除”记录的现有记录,则将适当条件添加到查询中以选择“已删除”记录。 这些API使开发人员对软删除过程透明,并消除了每次调用JPA API或发送JPQL查询时回答“删除或软删除”问题的负担。

这在大多数情况下都有效,但是在这个世界上没有完美的事物。为了灵活起见,CUBA仍然允许您执行本机SQL并获得对基础DataSource对象的访问。因此,即使使用解决了许多软删除实现问题的框架,您也需要仔细检查低级查询。

结论 即使对一个实体使用软删除,也会带您一堆新的开发约定。您需要记住,删除过程不仅是删除,而且有时更新和并非数据库表中的所有数据都可用于该应用程序。这意味着您应该对代码进行设计,使其在所有应用程序层中都将所有因素都考虑在内-从数据库架构(文档结构等)到用户界面(甚至如此)。使用适当的框架,您将能够解决所有这些问题,但您仍应记住,您已经“删除”了仍然存在的数据,并建立了将这一点考虑在内的编码标准和约定。


原文链接:http://codingdict.com