关于“数据完全版本记录”的系统设计

时间:2024年08月24日

作者:小蒋聊技术

邮箱:wei_wei10@163.com

微信:wei_wei10

音频:https://xima.tv/1_Gtthca?_sonic=0

++希望大家帮个忙!如果大家有工作机会,希望帮小蒋内推一下,小蒋希望遇到一个认真做事的团队,一起努力。需要简历可以加我微信。++

大家好,欢迎来到小蒋聊技术,小蒋准备和大家一起聊聊技术的那些事。

今天小蒋准备和大家一起聊的这个技术就厉害了!那就是"数据中的完全版本记录"设计。

昨天小蒋和大家一起分析了一个证券交易系统中的一个ER图。这个时候,有一个新的需求:请记录"数据中的完全版本记录",小蒋来试着分析一下。

当业务要求数据有完全版本记录时,系统需要确保每一笔数据变更都被详细记录下来,这样不仅可以在出现问题时回溯,还可以满足合规性和风险管理的需求。通常在金融和证券交易系统,医疗信息系统,交易支付系统,都会有这样的要求。这些系统对数据的准确性、可追溯性以及合规性有着严格的要求。为了实现这一目标,数据模型需要能够支持以下功能:

  1. 所有数据变更的记录和追踪:每次数据的更新、插入或删除操作都需要被记录,并保留每一个版本的数据。
  2. 高效的查询和数据恢复能力:系统必须能够高效地查询历史数据,并能够在必要时恢复到指定的历史状态。
  3. 性能优化:在高并发环境下,系统应尽量减少记录数据变更对性能的影响。

数据模型设计

核心业务表和历史记录表设计

我们在系统里基于ER图中的核心业务表(这些是原有的表),并为数据的完全版本记录引入了历史记录表。以下是具体设计:

核心业务表( ER 图中的原有表)

  • BOND_TR :记录债券交易的核心信息,包含每一笔交易的最新数据。
    • 字段
      • TradeId: 交易唯一标识,作为主键,用于标识每笔交易。
      • 其他字段:如交易类型、交易金额、交易时间等,存储最新的交易数据。
  • BOND :记录债券的详细交易信息,包括债券的种类、金额、期限等。
    • 字段
      • BondId: 债券唯一标识,作为主键。
      • TradeId: 外键,引用 BOND_TR 表中的 TradeId,用于关联具体的交易记录。
  • BD_PTSETL :记录交易的结算信息,保存结算金额、日期等关键数据。
    • 字段
      • SettleId: 结算唯一标识,作为主键。
      • TradeId: 外键,引用 BOND_TR 表中的 TradeId。

历史记录表(新增的表)

为了确保每次数据变更都被保存,我们引入以下历史记录表。这些表专门用于记录每次数据修改前的状态,保留所有版本的信息:

  • BOND_TR_History
    • 用途:存储 BOND_TR 表的历史版本。每次 BOND_TR 表中的数据发生变更时,旧版本会被复制到这个表中。
    • 字段
      • TradeId: 交易唯一标识,引用 BOND_TR 表中的 TradeId。
      • VersionNumber: 版本号,每次修改后递增,确保每个版本的数据唯一。
      • IsCurrent: 标识当前版本是否为最新版本(True 表示当前版本,False 表示历史版本)。
      • EffectiveDate: 版本生效时间,标识该版本数据何时生效。
      • EndDate: 版本结束时间,标识该版本何时被新的版本取代。

解释:

  • CreateTime 记录的是数据的创建时间,也就是第一次写入数据库的时间点。
  • EffectiveDate 则记录的是某个版本的数据开始生效的时间,通常在数据被修改时更新。

所以,尽管两个字段都涉及时间信息,但 EffectiveDate 是版本控制中的时间概念,而 CreateTime 是记录创建时的时间概念,它们的意义在数据生命周期中各有侧重,不可互换。

  • BOND_History
    • 用途:存储 BOND 表的历史版本。记录每次债券信息的变化。
    • 字段
      • BondId: 债券唯一标识,引用 BOND 表中的 BondId。
      • TradeId: 外键,引用 BOND_TR_History 表中的 TradeId。
      • VersionNumber: 版本号,和 BOND_TR_History 表中的 VersionNumber 保持同步。
      • IsCurrent: 标识当前版本是否为最新版本。
      • EffectiveDate: 版本生效时间。
      • EndDate: 版本结束时间。
  • BD_PTSETL_History
    • 用途:存储 BD_PTSETL 表的历史版本,确保所有结算信息的变化都能被追溯。
    • 字段
      • SettleId: 结算唯一标识,引用 BD_PTSETL 表中的 SettleId。
      • TradeId: 外键,引用 BOND_TR_History 表中的 TradeId。
      • VersionNumber: 版本号,与 BOND_TR_History 表中的 VersionNumber 保持一致。
      • IsCurrent: 标识当前版本是否为最新版本。
      • EffectiveDate: 版本生效时间。
      • EndDate: 版本结束时间。

设计细节的深入优化

为了确保数据完全版本记录模型在高并发场景下的有效性和性能,我们还需要进一步优化设计:

1. 乐观锁机制

为了确保数据一致性,我们采用乐观锁机制。在数据更新时,系统会检查当前记录的版本号是否匹配,如果版本号一致,则允许更新;如果版本号不一致,说明有其他操作修改过数据,这时系统会拒绝更新并提示用户重新提交。

2. 分区与分表策略

为了优化历史记录表的性能,我们可以按时间段(如季度或年度)对历史记录表进行分区,这样可以减少单个表的数据量,提升查询和写入效率。此外,对于数据量巨大的表,我们还可以采用分表策略,将数据按业务类型或其他规则分散存储在不同的表中。

3. 异步处理与缓存机制

为了降低历史数据写入对系统主业务流程的影响,我们可以使用异步处理机制。通过消息队列(如 Kafka )将旧版本数据发送到后台处理模块,异步写入历史记录表。这样主线程不必等待历史数据写入完成,可以提高系统响应速度。同时,使用 Redis 等缓存系统来存储常用的查询结果,可以进一步减轻数据库压力。

4. 异常情况下的数据一致性保证

使用异步处理机制时,最重要的是在异常情况下如何保证数据的一致性。我们可以通过以下方法来确保这一点:

  • 事务管理与回滚机制:通过将异步处理纳入事务管理,确保主事务提交时,异步任务也成功执行。如果异步处理失败,可以触发回滚机制,保持数据的一致性。
  • 消息队列的确认机制 :像 Kafka 这样的消息队列提供了确认机制,只有当消息被成功处理后,才会被标记为"已消费"。如果处理失败,消息会保留在队列中等待重新处理。
  • 幂等性设计:确保异步操作具有幂等性,即多次执行同一操作不会影响最终结果。通过在写入历史数据时检查是否已经存在相同的版本,避免重复写入,从而确保数据一致性。
  • 定期数据对账与补偿机制:通过定期对账,检查主业务表与历史记录表之间的数据是否一致。如果发现不一致,可以通过补偿机制重新处理未成功的操作。

5. 短事务管理与批量处理

在高并发环境下,短事务管理非常重要。尽量缩短每个事务的生命周期,减少数据库锁的持有时间,降低并发操作之间的冲突。同时,对于大量的数据更新操作,可以使用批量处理的方式,减少数据库连接和提交的开销,从而提升系统的整体性能。

总结

通过以上深入的设计,我们可以在确保系统高效运行的同时,满足数据完全版本记录的业务需求。这个数据模型设计能够为系统提供强大的数据追溯能力,并确保在高并发环境下的稳定性和性能表现。通过乐观锁机制、分区与分表、异步处理和短事务管理等策略,我们能够有效管理数据的历史版本,同时保持系统的高效性和可靠性。尤其在异常情况下,通过事务管理、消息队列确认、幂等性设计和补偿机制,我们可以确保数据的一致性,进一步提升系统的可靠性。

相关推荐
斗-匕1 分钟前
MySQL 三大日志详解
数据库·mysql·oracle
手握风云-4 分钟前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
代码中の快捷键7 分钟前
MySQL数据库存储引擎
数据库·mysql
只因在人海中多看了你一眼7 分钟前
数据库体系
数据库
隔着天花板看星星14 分钟前
Kafka-Consumer理论知识
大数据·分布式·中间件·kafka
holywangle15 分钟前
解决Flink读取kafka主题数据无报错无数据打印的重大发现(问题已解决)
大数据·flink·kafka
隔着天花板看星星16 分钟前
Kafka-副本分配策略
大数据·分布式·中间件·kafka
喵叔哟24 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生30 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
Lorin 洛林36 分钟前
Hadoop 系列 MapReduce:Map、Shuffle、Reduce
大数据·hadoop·mapreduce