我正在使用谷歌应用引擎并使用低级 java api 来访问大表。我正在构建一个有 4 层的 SAAS 应用程序:
- 客户端网络浏览器
- RESTful 资源层
- 业务层
- 数据访问层
我正在构建一个应用程序来帮助管理我的移动汽车美容公司(以及其他类似的公司)。我必须代表这四个独立的概念,但不确定我目前的计划是否是一个好的计划:
- 约会
- 订单项
- 发票
- 付款
预约: “预约”是指员工为了提供服务而需要在的地点和时间。
行项目: “行项目”是服务、费用或折扣及其相关信息。可能进入约会的行项目示例:
名称:价格:佣金:时间估算 完整细节,常规尺寸:160 75 3.5 小时 10 美元的全细节优惠券:-10 0 0 小时 高级细节:220 110 4.5 小时 派生总计(非行项目):370 美元 185 美元 8.0 小时
发票: “发票”是客户承诺支付的一个或多个行项目的记录。
付款: “付款”是对已收到的付款的记录。
在此应用程序的先前实现中,生活更简单,我将所有这四个概念都视为 SQL 数据库中的一个表:“约会”。一个“约会”可以有多个行项目、多个付款和一张发票。发票只是根据行项目和客户记录生成的电子邮件或打印件。
10 次中有 9 次,效果很好。当一位客户预约一辆车或几辆车并自己付款时,一切都很美好。但是这个系统在很多条件下都不起作用。例如:
- 当一位客户预约了一次,但预约中途下雨导致detailer第二天要回来,我需要两次预约,但只有一个line item,一张发票和一份付款。
- 当办公室的一群客户都决定在同一天完成他们的汽车以获得折扣时,我需要一个预约,但需要多张发票和多笔付款。
- 当一位客户用一张支票支付两次预约时,我需要两次预约,但只需要一张发票和一张付款。
我能够通过稍微捏造一些东西来处理所有这些异常值。例如,如果一个细部必须在第二天回来,我只需在第二天再预约一个项目,上面写着“完成”,费用将为 0 美元。或者,如果我让一位客户用一张支票支付两次约会,我会在每个约会中放入拆分付款记录。这样做的问题是它为数据不一致创造了巨大的机会。数据不一致可能是一个严重的问题,尤其是对于涉及财务信息的情况,例如第三个示例,其中客户用一张支票支付了两次约会费用。付款必须直接与提供的商品和服务相匹配,以便正确跟踪应收账款。
建议结构:
下面是用于组织和存储这些数据的规范化结构。也许是因为我缺乏经验,我非常重视数据规范化,因为这似乎是避免数据不一致错误的好方法。使用这种结构,可以通过一个操作完成对数据的更改,而不必担心更新其他表。但是,读取可能需要多次读取以及内存中的数据组织。稍后我想,如果存在性能问题,我可以在“约会”中添加一些非规范化字段,以便更快地查询,同时保持“安全”规范化结构完好无损。非规范化可能会减慢写入速度,
表:
Appointment
start_time
etc...
Invoice
due_date
etc...
Payment
invoice_Key_List
amount_paid
etc...
Line_Item
appointment_Key_List
invoice_Key
name
price
etc...
以下是将给定约会列表的所有四个实体(表)联系在一起所需的一系列查询和操作。这将包括关于每次预约安排了哪些服务、每次预约的总费用和天气或每次预约未收到付款的信息。这将是加载日历以进行约会安排或经理获取运营整体视图时的常见查询。
- 查询“开始时间”字段位于给定范围之间的“约会”列表。
- 将返回的约会中的每个键添加到列表中。
- QUERY 对所有“Line_Items”的约会键列表字段包括任何退货约会
- 将所有行项目中的每个 invoice_key 添加到 Set 集合中。
- 查询发票集合中的所有“发票”(这可以使用应用引擎在一个异步操作中完成)
- 将返回的发票中的每个键添加到列表中
- 查询所有“付款”,其中 invoice_key_list 字段包含与任何返回的发票匹配的键
- 在内存中重新组织,以便每个约会都反映为其安排的 line_items、总价格、总估计时间以及天气是否已支付。
...如您所见,此操作需要 4 个数据存储查询以及一些内存中的组织(希望内存中会很快)
任何人都可以评论这个设计吗?这是我能想到的最好的,但我怀疑可能有更好的选择或完全不同的设计,我没有想到这可能会在一般情况下或特别是在 GAE(谷歌应用引擎)的优势、劣势和能力下更好地工作.
谢谢!
使用说明
大多数应用程序的读取密集度更高,有些应用程序的写入密集度更高。下面,我描述了一个典型的用例并分解了用户想要执行的操作:
经理接到客户的电话:
- 读取- 经理加载日历并查找可用时间
- 写入- 经理向客户查询他们的信息,我将其想象为一系列异步读取,因为经理输入每条信息,例如电话号码、姓名、电子邮件、地址等......或者如果有必要,也许一个在客户端应用程序收集所有信息并提交之后,在最后写入。
- 写入- 经理记下客户的信用卡信息并将其作为单独的操作添加到他们的记录中
- 写入- 经理向信用卡收费并验证付款是否通过
经理拨出电话:
- 读取管理器加载日历
- 读取经理为他要呼叫的客户加载约会
- Write Manager 点击“Call”按钮,发起一个调用并写入一个新的 CallReacord 实体
- 读取呼叫服务器响应呼叫请求并读取 CallRecord 以了解如何处理呼叫
- 写入呼叫服务器将更新的信息写入呼叫记录
- 调用关闭时写入,调用服务器向服务器发出另一个请求以更新 CallRecord 资源(注意:此请求不是时间关键的)
接受的答案:: 前两个答案都非常周到和赞赏。我接受了一个票数很少的人,以便尽可能不完美地平衡他们的曝光率。