ORM到底解决什么问题
什么是ORM
ORM(对象关系映射,Object-Relational Mapping)是一种编程技术,用于在关系型数据库和面向对象编程语言之间建立映射关系,从而让开发者能够以操作对象的方式间接管理数据库数据。
核心原理:
- 映射规则:
- 数据库表 ↔ 类(Class)
- 表的每一行 ↔ 类的实例(对象)
- 表的字段 ↔ 对象的属性
功能特性:
- 自动生成SQL:开发者调用
user.save()
即可触发INSERT
语句,无需手写。 - 查询封装:提供类似
User.query.filter_by(name='Alice')
的链式语法,替代原生SQL。 - 事务管理:简化数据库事务的提交、回滚操作。
- 跨数据库兼容:通过适配层支持MySQL、PostgreSQL等不同数据库,切换时仅需修改配置。
示例(Python Django ORM):
# 定义模型(对应数据库表)
class User(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
# 操作数据库
new_user = User(name="李华", age=25)
new_user.save() # 自动执行INSERT语句
users = User.objects.filter(age__gt=20) # 生成SELECT * FROM user WHERE age > 20
优势 vs 直接SQL:
场景 | ORM | 原生SQL |
---|---|---|
简单CRUD | 代码简洁,开发速度快 | 需拼接字符串,易出错 |
复杂查询 | 可能需结合原生SQL或特殊语法 | 直接编写更灵活 |
多数据库支持 | 改配置即可切换数据库 | 需重写大量SQL语句 |
防止SQL注入 | 自动参数化查询,默认防注入 | 需手动处理参数,否则高危 |
典型框架:
- Python:Django ORM、SQLAlchemy
- Java:Hibernate、MyBatis
- JavaScript:TypeORM、Sequelize
潜在问题:
- 性能损耗:自动生成的SQL可能不够优化,复杂查询需手动干预。
- 学习成本:需掌握特定ORM的查询语法和配置规则。
简言之,ORM如同翻译官,让程序用“对象语言”与数据库的“SQL语言”无缝沟通,提升开发效率,但需权衡灵活性与性能。
以上对ORM的解释源于 DeepSeek
优点
解决的问题
- 管理数据库schema的创建和迁移(变更)。
- 自动绑定查询结果到具体语言,或者让语言在具体CRUD上的更简单。
- 基于函数调用、表达式的数据库查询,代替SQL,减少使用SQL处理简单查询时的频率(这个代替不完全)。
a. 防止SQL注入风险
b. 实现绑定参数,简化编程语言将对象帮到SQL
c. 隐含权限管控到数据库操作 - 支持多个数据库后端,方便业务开发时切换更换数据库,减少因为数据库替换后带来的迁移风险(有限的能力,有限的场景)
- 隐含Schema数据库规范。
- 附带缓存,降低数据库负担。
缺点
表达能力有限
- ORM只囊括了数据库操作的子集,一旦脱离ORM使用者还是变得难以适从。
- 多后端支持在绝大多数业务场景中用不到,在BI工具开发时才会带来真正的收益。这种基于多种数据库后端的抽象,进一步限制了适配具体数据库的特性,最终兼容的数据库种类越多,对于特定数据库的支持越弱,难以将指定数据库的特性全部发挥出来。
额外的学习成本
- 脱离SQL但依然要学习新的表达方式,来组合构建出SQL查询,比如Odoo查询中的域操作:与、或、非需要用波兰(前缀)表达式,这种表达形式是反常规的,对于主流开发语言的开发者,中缀表达式才是他们熟悉的日常表达形式。也许您会说,不就是运算符号从中间换到了最前面吗,其实不然,请看下面的举例
# 合法的波兰表达式
['|','&','|',a,b,c,'&',d,e]
# 替换为中缀表达式后
[(((a| b) &c)| (d & e))]
不经过反复训练的人看到波兰表达式也很难想到替换为中缀的写法。ORM的设计不一定遵从大家在SQL或者开发语言上的习惯,而反习惯的东西会进一步提高大家的学习成本,于是造就了大多数人都学过SQL,但这对于理解ORM不一定有用的现象。
性能折扣
- 这是大多数ORM都存在的问题,造成这种局限的原因有两个:
a. ORM生成的SQL语句并非性能最佳,事实上ORM大多精力都花在如何构造出可以查询的语句,对于优化无能为力。
b. SQL语言的语法并不是一个易扩展、易解构的表达,这种情况导致它难以被ORM的查询构造器结构、重组、优化。
隐藏性
- ORM通常都简化了对FROM数据表的书写,这在线上问题定位时会造成很大的阻碍,比如我知道线上问题发生在A表,但我无法在代码中搜索到所有使用A表的代码,“聪明”的ORM自动隐藏了它,通过Schema建模管理ORM可以自动找出部分SELECT的来源表,这种隐藏在开发时是方便的,但在运维时是可怕的负担。
- 隐藏性还体现在对SQL构建的时候,无法通过ORM自身未提供的手段去优化生成语句,最终可能出现使用或不用ORM的选择,而不用以为这你要熟悉SQL和数据库,这是又将产生另一个权衡,既然我熟悉了数据库和SQL,是不是意味着我用ORM造成了更多额外负担。当然这个负担的根源是ORM无法满足一个业务系统所有数据库操作需求。
- 数据库迁移,许多ORM是通过差异比较的方式进行的,整个操作又是隐式自动的,在数据库迁移操作审核和回退恢复方面是无踪迹可循,不符合许多开发团队的SQL上线流程,有额外的使用风险。
缓存
- 缓存的使用时通常要考虑具体场景,主要是对一致性的考量,比如Odoo中ORM缓存会强一致去同步,同步依据数据库自增序列作版本号,最终每次还是会查询数据库,只是将查询数据库的不确定时间,变为查询版本号的常量时间,另外副作用还有无变更时同样付出了数据库查询。这种方式并非不好,只是缺乏应对多种场景的灵活性,而过度的强一致同步,在分布式系统中,无疑是扩展的枷锁,越水平扩展,带来的损耗越大,大大缩小了水平扩展带来的直接收益,也让扩展更早的进入减益。
综上,可以看出ORM在数据库Schema管理上似乎优势更加明显,其它地方则需要更多的权衡。
更好的ORM
或者说应用程序开发者对数据库管理更好的办法是什么?没回答好这个问题就一直受ORM副作用影响,或是SQL直接操作的低效、难维护、不安全。
• 只支持一种数据库,并持续支持更多的数据库新特性,亲近特定数据库,充分发挥特性,简化开发者使用难度。
• 放弃直接使用SQL查询数据,也不要直接解构并用另一种语言发明构造SQL构造器。而是直接采用数据库自身的SQL查询语句,充分利用其特点。
• 为Schema的约束建立应用开发层的数据校验,防止开发人员的的误操作、检查遗漏让数据库变脏。
• 框架不该隐藏操作,不做全封闭黑盒,留出扩展、补间余地,给开发者解决特殊问题开辟通道,以免用到中途无路可走。
• 提供更多缓存方案,或者只提供对架构影响较小的缓存方案,避免成为架构调整的绊脚石。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示