Saas.扩展字段 自定义字段

为什么需要扩展字段

一个产品不可能罗列出所有的字段,比如:员工表,你能罗列所有企业OA系统中员工的信息字段吗? “不可能的”。 咱也别有穷举这种妄念。管理方面理解: 固定规则和自由度需要结合起来,总公司不能把子公司规定死死的,也需要给一定的自由度灵活处理。固定规则为了保证秩序,业务系统中是为了保证系统可以正常运行,自由度是为了适配各地各种没有预想到的场景,业务系统中就是预留可扩展字段给用户,这样方可为上册。

多一嘴:有一些人只是从技术角度看系统,说明他只在看山还是山的第一层。搞Saas的都再这一层会遇到天花板的。Saas其实是做一个平台,这个平台要可以兼容解决大千世界无数场景的问题,就需要设计一套原则或者制度来保证都能处理到,这个维度看,不就跟中央要设计一个制度去治理一个国家吗? 如果你能想到可能的问题,可以留言讨论,想不到可能的问题说明理解不了,直接跳过这段。

方案选型

1. 文档型数据库

2. 关系型数据库(横表) + JSON

3. 关系型数据库(纵表)

4. 关系型数据库(横表) : 固定业务字段 + 预留字段 + 元数据

5. 关系型数据库(横表) : 固定系统字段 + 预留字段 + 元数据

6. 列数据库Hbase

7. 混合方案,举例Salesforce

文档型数据库

MongoDB,存储的是Json啥都可以存储

缺点:事务支持不怎么好;数据不直观,增加后面运维的难度;复杂的join不支持;

从考虑到放弃: 字段不确定很容易想到存储JSON的MongoDB,然而毕竟涉及思想不同,现有开发思想大部分是基于关系型二维表,开发涉及过程的管理,生态和工具的支持,以及二维表天然的数据不会冗余特性,真正冗余了怎么保证数据的一致性,或者说你怎么能确定数据没有冗余。比如:订单中存储了详情的数据,然这样的数据到底有多少,经过几年的开发和人员流通后你能知道?

总结:如果只从是否可实现的角度看,可以。但加上其他因素不可以。

关系型数据库(横表) + JSON

Mysql+JSON字段(5.8 以上版本)

缺点:
1、从json中去统计某个字段数据之类的很麻烦,而且效率低。
2、查询相对效率较低,操作复杂。
3、更新其中某个字段效率较低,不适合存储业务逻辑复杂的数据。
4、统计数据复杂,建议需要做报表的数据不要存json。

总结:如果不需要根据json来统计数据或者局部更新json,仅是简单的读取或者整体覆盖,对于需要存取一个很大的有结构的数据,那json是较佳选择。

试用场景:扩展的字段只是用来做信息的补充,可以按照值对象(DDD中将省市县这种分开查询的比较少的场景就存储为一个json串)存储

Mysql+MongoDB

比较鸡肋,涉及到夸数据库操作,并且不同类型。还不如只有Mysql或者只用MongoDB呢

Mysql+JSON字段+MongoDB

MongoDB作为JSON数据的缓存

或者MongoDB作为Mysql中数据的缓存来查询,冗余了数据但兼容了有点

缺点:数据一致性保障,对开发和框架有要求

关系型数据库(纵表)

什么是纵表

  1. 属性值 依赖 某个品类的某个对象(对象ID)的 某个属性值(属性ID),且某个对象的属性值可变,又没法记录,但属性值在某时刻或者某时间段(时间区间)是固定值,所以才可记录
  2. “是否当前有效”标识是否是 对象的当前(现在)的属性值
  3. “是否有效”标识 该数据是否有用,可能是错误数据,删除了,没用了。

 没有优点和不足

只是一种方案,这么存储数据效率太低了。看也不好看, 查询和统计等操作都用不上了。知道有这么一种方案就行。

关系型数据库(横表) : 固定业务字段 + 预留字段 + 元数据

固定的字段(业务字段,系统标识字段)

var1 var2 int1 int2 为预留字段,到底啥意思,需要看元数据怎么描述

 元数据表,示例:

场景:适合固定业务,需要扩展一些信息

优点:实现简单,还在二维表中操作,现有框架都可以用,数据呈现清晰

不足:需要元数据表辅助才可以清楚扩展字段的含义;预留的字段如果没有扩展字段,浪费空间

关系型数据库(横表) : 固定系统字段 + 预留字段 + 元数据

对上面的更一步抽象,既然元数据能描述字段是啥意思,那么能否将:“客户名称”“客户电话”“客户电话”等业务字段也描述了,答案是可以的。

元数据表:可以看出固定字段重复描述了


不足:如果涉及字段修改,需要刷元数据表(不要小看这个问题,后续解决Bug的时候会是一个负担) 好处:好处是可以对这个字段名称重命名了。

列数据库Hbase

1. 列数据库是按照列来组织数据,适合一次更新:多个学生的,姓名字段。而行数据库适合更新一个学生的多个属性。

2. 列数据库是OLAP(分析),行数据库是OLTP(事务处理)

3. 列数据库适合在某列上做聚合操作,行数据库适合对一行数据进行操作。

实际业务系统,虽然说列数据库可以节省点空间,但并不适合事务性场景的业务处理;

简单说就是:列数据库可以稍微矮点边,但终究他是为了数据分析设计的, 不适合业务处理数据的存储。

混合方案,举例Salesforce

将数据存储封装为一个服务:包括建表(实体),表的唯一主键,业务联合主键,字段完整性校验; 将查询单表封装为API,如果可以暴露出来Sql访问就可以了,完全用Sql去DB执行需要熟悉底层表的逻辑,后续成本会指数上升,这指的是,实现了Sql协议的服务。

方案选型

根据Saas平台迭代过程,一般会选择:

关系数据库 --》 关系数据库+sql字段 --》 sql字段如果有统计或者join可以替换为MongoDB

                  --》 固定字段+扩展字段+元数据 --》系统字段+元数据 --》混合型的元数据驱动方案

持久化方案后续问题

1.  持久化方案 要不要独立,独立后要不要 必须规范化,最好能统一查询语言,屏蔽底层逻辑

2.  定位问题,小租户和大数据量租户共存,怎么优化数据

3.  数据量超过kw级别,分表分库的需求。一定会有,日志文件一定会超

参考文档

科学网—面向列的数据库 - 唐李洋的博文

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
对于 SaaS 多租户应用中的字段隔离,控制层需要负责从请求中获取租户 ID,并将其传递给业务逻辑层进行处理。这可以通过 AOP 技术实现,在请求执行前将租户 ID 注入到业务逻辑层的方法参数中。 下面是一个示例代码: ```java @Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; // 业务逻辑层 @GetMapping("/{id}") public ResponseEntity<User> getUserById(@PathVariable("id") Long id, @RequestParam("tenantId") Long tenantId) { User user = userService.getUserById(id, tenantId); if (user == null) { return ResponseEntity.notFound().build(); } return ResponseEntity.ok(user); } @PostMapping public ResponseEntity<User> createUser(@RequestBody User user, @RequestParam("tenantId") Long tenantId) { userService.createUser(user, tenantId); return ResponseEntity.status(HttpStatus.CREATED).body(user); } @PutMapping("/{id}") public ResponseEntity<User> updateUser(@PathVariable("id") Long id, @RequestBody User user, @RequestParam("tenantId") Long tenantId) { User existingUser = userService.getUserById(id, tenantId); if (existingUser == null) { return ResponseEntity.notFound().build(); } existingUser.setName(user.getName()); existingUser.setEmail(user.getEmail()); userService.updateUser(existingUser); return ResponseEntity.ok(existingUser); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable("id") Long id, @RequestParam("tenantId") Long tenantId) { User existingUser = userService.getUserById(id, tenantId); if (existingUser == null) { return ResponseEntity.notFound().build(); } userService.deleteUser(existingUser); return ResponseEntity.noContent().build(); } } ``` 在这个示例中,我们在每个方法的参数列表中添加了 @RequestParam("tenantId") 注解,用于从请求中获取租户 ID。在具体业务逻辑的实现中,我们需要将租户 ID 作为参数传递给业务逻辑层的方法进行处理。这样就可以实现对不同租户的数据进行隔离。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值