时间:2024年08月25日
作者:小蒋聊技术
邮箱:wei_wei10@163.com
微信:wei_wei10
音频:https://xima.tv/1_JAlD44?_sonic=0
希望大家帮个忙!如果大家有工作机会,希望帮小蒋内推一下,小蒋希望遇到一个认真做事的团队,一起努力。需要简历可以加我微信。
大家好,欢迎来到小蒋聊技术,小蒋准备和大家一起聊聊技术的那些事。
今天小蒋准备和大家一起聊的这个技术就厉害了!那就是一个证券交易系统的设计。
1. 提出原因或需求
在现代证券交易系统中,满足以下需求至关重要:
- 数据的完全版本记录:每一次数据的变更都必须被详细记录,以确保合规性和审计能力。
- 前端的灵活性:系统需要支持前端随时根据业务需求增加新的业务字段,而不需要对系统的核心结构进行大规模重构。
- 系统的可扩展性:后端必须能够动态处理和存储新增加的字段,确保系统能够快速适应业务需求的变化。
2. 数据模型设计:支持完全版本记录
业务需求:为了满足业务需求,所有数据变更必须有完整的版本记录,允许追溯历史版本。
数据模型设计方案:
- 版本控制的数据模型设计:
- 主数据表与历史版本表:
- 主表:ER图中的核心实体(例如BOND)记录当前最新的数据版本。
- 历史版本表:例如BOND_HISTORY表,记录所有历史版本数据。
- 字段设计:
- VersionNo:版本号,用于标识每次变更的数据版本。
- IsActive:标识当前记录是否为最新版本。
- EffectiveDate 和 EndDate:记录版本的生效和结束日期。
- 版本管理逻辑:
- 每次修改核心实体表中的数据时,旧版本会被存入历史表,并更新EndDate字段。
- 新版本的记录会更新到核心实体表中,并生成一个新的VersionNo,设置IsActive为1。
- 主数据表与历史版本表:
3. 前端结合设计:数据栏位、校验与数据生命周期处理
数据栏位设计:
- 核心业务字段:在前端,核心实体(如BOND)中的主要字段通过表单控件展示给用户,如BondName、TradeId等。
- 版本控制字段:VersionNo、IsActive等版本控制字段不会直接展示给用户,但在查看历史版本时,可以以只读模式显示。
- 动态扩展字段:
- 动态生成:使用前端框架(如React、Vue.js)动态生成新增字段的输入控件。例如,通过API获取配置,动态生成所需的文本框、下拉菜单等。
整体校验设计:
- 前端校验:
- 必填字段校验:前端使用required属性或自定义脚本,确保用户填写所有必填字段。未填写时,给予即时反馈(如高亮显示或提示信息)。
- 数据类型校验:使用HTML5的内置校验功能(如type="email"、type="number")或自定义校验函数,确保用户输入符合预期类型。
- 格式校验:对于特定格式的字段(如日期、金额),前端通过正则表达式或特定的输入控件进行格式校验。
- 逻辑校验:确保数据之间的逻辑关系正确,如EndDate必须晚于EffectiveDate。
- 后端校验:
- 复杂业务逻辑校验:后端负责对提交的数据进行深入的业务逻辑校验,以确保数据的准确性和合法性。
- 并发控制:使用乐观锁或其他机制,确保高并发下数据的一致性。
数据生命周期处理:
- 版本管理:
- 前端处理:用户提交修改时,前端显示当前版本信息,并提示用户变更的版本号。
- 后端处理:后端生成新版本并将旧版本归档至历史表,管理EffectiveDate和EndDate字段。
- 版本历史查看:前端通过API调用后端的历史数据接口,展示历史版本信息。
- 审批与归档:
- 前端处理:在需要审批的流程中,前端会显示当前的审批状态,并禁止用户进一步修改,直到审批完成。
- 后端处理:后端执行审批流程,更新数据状态,并在必要时将数据归档。
- 自定义生命周期动作:
- 前端触发:用户可以通过前端界面触发特定的生命周期操作(如重新审核、数据恢复等)。
- 后端执行:后端接收前端的触发请求后,执行具体的生命周期管理操作,例如,重新激活归档数据、更新状态等。
4. 实体的扩展与定制
实体扩展的设计思路:
- 使用EAV模型(Entity-Attribute-Value)
EAV模型的核心思想:
- 灵活性:EAV模型的核心目的是提供极大的灵活性,允许在同一个表中存储不同实体的各种属性,而这些属性可能是动态的、可变的,并且可能在不同实体之间有所差异。
实现步骤:
- 创建属性表:例如,为Bond实体创建BondAttributes表,结构如下:
- EntityId:指向实体主表的外键,例如BondId。
- AttributeName:属性名称,如RiskLevel、MarketSegment。
- AttributeValue:属性值,通常为字符串或其他通用数据类型。
应用场景:
- 广泛应用场景:适用于需要存储大量不同属性,而这些属性可能是稀疏的或频繁变化的场景。例如,一个产品可能有“颜色”和“尺寸”,另一个产品可能有“电池容量”和“屏幕大小”。
优点:
- 高度灵活:可以动态增加属性而无需修改数据库结构。
- 适应变化:适合那些数据结构变化频繁或不同实体属性各异的场景。
缺点:
- 复杂性增加:由于属性和值存储在不同的记录中,查询和操作可能变得更为复杂,特别是在需要对多个属性进行筛选时。
- 使用JSON字段存储
JSON存储的核心思想:
- 嵌套数据存储:在主表中使用JSON字段存储扩展属性,可以灵活存储多层次、复杂结构的数据。
实现步骤:
- 新增JSON字段:在BOND表中增加AdditionalData字段,类型为JSON,示例结构如下:
{
"RiskLevel": "High",
"MarketSegment": "EMEA",
"CustomAttributes": {
"Attribute1": "Value1",
"Attribute2": "Value2"
}
}
- 前后端处理:
- 前端:在表单提交或展示时,解析和构建JSON数据。
- 后端:处理JSON数据,确保其符合业务逻辑需求。
优点:
- 灵活性高:可以在一个字段中存储多层次、不同类型的复杂数据结构。
- 适合嵌套数据:特别适用于存储嵌套或关联属性的数据。
缺点:
- 性能影响:虽然灵活性高,但在进行查询、筛选和排序时,性能可能不如传统结构化数据。
- 使用属性表关联模式
属性表关联模式的核心思想:
- 分离属性管理:为每个需要扩展的实体创建单独的属性表,与主实体通过外键关联,集中管理所有扩展属性。
实现步骤:
- 创建关联表:例如,为Bond实体创建BondAttributes表,结构如下:
- AttributeId:属性的唯一标识符。
- BondId:关联到主实体表的外键(例如BOND表)。
- AttributeName:属性名称。
- AttributeValue:属性的具体值。
应用场景:
- 专用扩展:属性表关联模式更专注于为特定实体扩展额外的属性,通常这些属性是与业务逻辑紧密相关的,且属性的数量和类型是相对确定的。
优点:
- 清晰管理:结构清晰,易于理解和维护,特别适用于属性数量适中、变化频率中等的场景。
- 性能较好:相较于EAV模型,查询性能可能较优,尤其是在属性数量有限的情况下。
缺点:
- 灵活性受限:相比于EAV和JSON存储,在属性多样性和扩展性上略显不足。
5. 校验与自动填充
校验与自动填充的扩展设计:
在属性需要扩展的情况下,系统需要具备以下能力,以确保新增属性的数据质量和一致性。
1. 前端校验与自动填充
前端校验的设计:
- 动态校验规则:
- 配置驱动的校验:当新增属性时,前端可以通过配置文件或API动态加载校验规则。比如,针对某个新增的RiskLevel属性,可以设置格式(如数字格式)、范围(如0-100)的校验。
- 正则表达式校验:前端根据属性类型使用正则表达式对用户输入进行即时校验。例如,日期字段使用yyyy-mm-dd格式校验。
自动填充的设计:
- 基于依赖关系的自动填充:
- 属性依赖关系:某些属性可能依赖于其他属性的值。例如,选择了BondType后,系统可以自动填充默认的RiskLevel或其他关联属性。前端可以根据用户选择动态调整或自动填充这些属性。
前端UI动态生成:
- UI组件动态生成:
- 根据属性类型生成控件:根据属性的数据类型(如字符串、日期、数字),动态生成相应的输入控件(如文本框、日期选择器、下拉列表),并自动附加校验逻辑。
2. 后端校验与自动填充
后端校验的设计:
- 多层次校验逻辑:
- 属性类型校验:后端需要根据属性的类型进行数据类型校验,例如验证日期格式的正确性或数值的范围。
- 业务逻辑校验:如在提交时验证MaturityDate是否晚于IssueDate,或者RiskLevel是否在合理的范围内。
自动填充的设计:
- 规则驱动的自动填充:
- 基于业务规则的自动填充:后端在处理请求时,可以根据业务规则为某些属性自动生成默认值或计算值。例如,当用户提交一个BondType时,系统可以根据预定义规则自动填充其相关的RiskLevel。
持久化动态属性:
- 灵活存储方案:
- JSON或EAV存储:新增的动态属性可以通过JSON字段或EAV模型进行存储,后端在接收到前端数据后,解析并根据业务规则进行存储和处理。
6. 数据生命周期管理的定制
前端触发与后端执行:
- 用户操作:前端允许用户触发特定的生命周期动作,如数据归档、状态更新等。用户可以通过按钮或操作菜单选择这些动作。
- 后端处理:后端根据用户的操作请求,执行相应的业务逻辑。例如,当用户选择“归档”操作时,系统会自动将数据移入归档表,并更新状态字段。
定期任务与事件驱动:
- 定期任务:后端可以设置定期任务,如每天自动检查并处理达到归档条件的数据。可以使用任务调度器或定时任务服务来实现。
- 事件驱动:在业务逻辑中添加事件触发机制。例如,当MaturityDate到达时,系统自动触发状态更新或通知用户进行进一步操作。
7. 基于生命周期动作定制的实体扩展
当业务要求对数据的生命周期动作进行定制时,实体的扩展需要支持动态状态管理、事件驱动和定期任务处理。以下是如何根据这些需求设计系统。
1. 使用状态机模式管理生命周期
状态机的核心思想:
- 状态与动作:使用状态机模式来管理实体的生命周期。每个实体都有多个可能的状态,每个状态可以触发不同的动作或导致状态转换。
实现步骤:
- 状态字段:在核心实体表中增加Status字段,用于标识当前生命周期状态。
- 状态机配置:定义一个StateMachine配置表,用于存储状态转换规则和对应的生命周期动作。例如:
- CurrentState:当前状态(如Active、Matured)。
- NextState:下一状态(如Archived)。
- Action:触发的动作(如SendNotification、GenerateReport)。
- Condition:状态转换条件(如MaturityDate到达)。
应用场景:
- 自动化流程管理:当某个条件满足时,系统自动根据状态机规则更新实体的状态,并执行相应的动作。例如,当债券到期时,状态从Active转换为Matured,系统自动生成到期报告并通知相关方。
优点:
- 灵活性:状态机模式可以轻松配置和扩展,适应多变的业务需求。
- 可维护性:清晰的状态和动作定义,使得系统逻辑易于理解和维护。
2. 使用事件驱动架构
事件驱动架构的核心思想:
- 基于事件触发动作:使用事件驱动架构来响应数据生命周期中的关键事件,例如状态变更、数据更新或条件满足。
实现步骤:
- 事件日志表:创建一个EventLog表,用于记录和管理系统中的关键事件。
- EventId:事件的唯一标识符。
- EntityId:关联的实体ID,例如BondId。
- EventType:事件类型,例如MaturityReached。
- Timestamp:事件发生时间。
- Processed:事件是否已被处理。
- 事件处理器:实现事件处理逻辑,根据事件类型触发相应的生命周期动作。例如,当MaturityReached事件被触发时,系统自动执行相应的归档操作。
应用场景:
- 事件触发动作:当特定事件发生时,系统可以立即响应并执行相应的动作,例如发送通知、归档数据或更新状态。
优点:
- 实时性:事件驱动架构能够实时响应并处理系统中的关键事件。
- 扩展性:通过增加新的事件类型和处理器,系统可以轻松扩展和适应新的业务需求。
3. 使用定期任务和批处理
定期任务的核心思想:
- 定时检查与处理:使用定期任务来周期性地检查数据的生命周期状态,并执行相应的操作。
实现步骤:
- 任务调度:使用任务调度器(如Quartz或内置的定时任务服务)来定期执行任务。
- 定期任务可以检查即将到期的债券,并将其状态更新为Matured,然后触发相应的生命周期动作。
- 批处理作业:对于需要大量数据处理的操作(如批量归档、数据清理),可以通过批处理作业来执行,避免实时处理带来的性能影响。
应用场景:
- 定期归档:每天夜间系统会自动检查到期的债券,并将其归档到历史表中。
- 数据清理:定期清理无效或过期的数据,确保系统的高效运行。
优点:
- 效率高:定期任务适合处理大批量数据,降低系统的实时负载。
- 稳定性:通过批处理减少高峰时段的负载,确保系统稳定性。
总结
在本次详细的设计方案中,我们不仅涵盖了如何在证券交易系统中实现数据的完全版本记录、前端结合设计、数据生命周期管理,还深入探讨了如何扩展实体以支持属性扩展下的校验与自动填充,以及数据生命周期动作的定制。
通过结合动态校验、自动填充逻辑、状态机管理、事件驱动架构和定期任务管理,系统能够灵活地处理各种定制化的数据生命周期动作。这种设计不仅能适应复杂的业务流程,还能随着业务的变化而灵活调整,为构建一个智能、高效且可扩展的证券交易系统提供了坚实的技术基础。如果有进一步的需求或问题,欢迎继续探讨!