注:本文为 "ORM" 相关合辑。
中文引文,略作重排。
如有内容异常,请看原文。
ORM 框架介绍------什么是 ORM 框架
发布时间:2022-07-20 10:21
作者:jiuchengi
1 概念定义
对象关系映射(Object Relational Mapping,简称 ORM \text{ORM} ORM),是适配面向对象编程范式与关系型数据库数据存储范式的技术形式。
ORM \text{ORM} ORM 框架可作为程序与数据库之间的交互载体,配置持久化类与数据表的映射规则后,程序运行阶段框架可依据映射配置,完成程序对象向数据库的数据写入操作。
当前主流 ORM \text{ORM} ORM 框架包含五类:
- Hibernate \text{Hibernate} Hibernate:全自动映射框架,业务逻辑编写依托 HQL \text{HQL} HQL 语句
- iBATIS \text{iBATIS} iBATIS:半自动映射框架,支持自定义编写 SQL \text{SQL} SQL 语句,具备灵活操控性,程序体量轻便
- MyBatis \text{MyBatis} MyBatis
- EclipseLink \text{EclipseLink} EclipseLink
- JFinal \text{JFinal} JFinal
2 技术应用价值
未引入 ORM \text{ORM} ORM 机制的应用程序,数据访问层会存在大量同质化代码,数据新增、删除、读取等基础操作均需要重复编写对应逻辑。
引入 ORM \text{ORM} ORM 机制能够缩减重复代码体量,该技术体系可完成程序对象与关系型数据库数据之间的映射转换。
3 对象-关系映射特性
-
结构简约
ORM \text{ORM} ORM 依照基础逻辑完成数据建模,可将 MySQL \text{MySQL} MySQL 数据表映射为编程语言类结构,数据表字段对应类内部成员变量。 -
映射标准统一
所有 MySQL \text{MySQL} MySQL 数据表按照固定规则转换为程序类结构,程序代码层级的数据格式可保持统一规范。
-
结构可读性良好
数据库存储结构可通过映射关系转换为程序代码结构,开发人员可依托编程语言逻辑理解数据库架构。
-
操作接口完备
框架封装持久化对象的增删改查接口,包含 create() \text{create()} create()、 update() \text{update()} update()、 save() \text{save()} save()、 load() \text{load()} load()、 find() \text{find()} find()、 find_all() \text{find\_all()} find_all()、 where() \text{where()} where() 等方法。原始 SQL \text{SQL} SQL 语句被封装为程序函数,通过函数链式调用拼接生成执行语句,能够规避格式杂乱、冗余度偏高、编写风格差异化的 SQL \text{SQL} SQL 代码,减少人为代码异常,统一编码规范,降低后期维护难度。

4 ORM 技术特性
4.1 正向特性
- 缩减项目开发周期,控制开发投入成本
- 代码编写逻辑贴合面向对象设计思想
- 具备跨数据库运行适配能力
- 可便捷拓展数据缓存类附属功能
4.2 反向特性
- 自动映射流程会占用设备运算资源,常规业务场景下资源消耗处于可接受范围
- 多表关联查询、多条件筛选等复杂数据检索场景中, ORM \text{ORM} ORM 语法编写复杂度会同步提升
ORM 实例教程
作者:阮一峰
日期:2019 年 2 月 18 日
一、概述
面向对象编程与关系型数据库均为通用技术体系,二者数据组织模型存在差异。面向对象编程将业务实体封装为对象实例,关系型数据库依托实体关联关系完成数据存储。业界提出以对象形式描述数据关联关系,以此实现依托面向对象语法操作关系型数据库。
ORM \text{ORM} ORM 为对象关系映射(Object/Relational Mapping)的缩写,依托实例对象语法实现关系型数据库的各项操作。
ORM \text{ORM} ORM 建立数据库结构与程序对象的对应关联:
- 数据表(table) → \rightarrow → 程序类(class)
- 数据记录(record) → \rightarrow → 对象实例(object)
- 数据表字段(field) → \rightarrow → 对象属性(attribute)
以数据查询语句为例,原生 SQL \text{SQL} SQL 写法如下:
javascript
SELECT id, first_name, last_name, phone, birth_date, sex
FROM persons
WHERE id = 10
直接执行语句操作数据库的编码形式:
javascript
res = db.execSql(sql);
name = res[0]["FIRST_NAME"];
转换为 ORM \text{ORM} ORM 编码形式:
javascript
p = Person.get(10);
name = p.first_name;
对比可见, ORM \text{ORM} ORM 以对象机制封装数据库操作,编码过程无需编写原生 SQL \text{SQL} SQL 语句。开发人员基于面向对象逻辑与数据对象交互,无需关注底层数据库运行机制。
ORM 应用优势
- 数据模型集中定义,便于迭代调整与复用开发
- 配套工具可自动完成数据清洗、预处理、事务管控等流程
- 适配 MVC \text{MVC} MVC 架构设计,模型层级划分清晰,代码结构规整
- 业务代码语句简洁,语义直观,便于代码阅读
- 规避低效 SQL \text{SQL} SQL 语句编写问题
ORM 应用局限
- 框架体量偏大,框架学习与参数配置需要投入时间
- 复杂检索场景下,部分逻辑无法通过 ORM \text{ORM} ORM 语法实现,执行效率不及原生 SQL \text{SQL} SQL
- 底层数据库运行逻辑被封装屏蔽,定制化特殊语句编写存在限制
二、命名规范
各类编程语言均配套专属 ORM \text{ORM} ORM 工具库, Ruby \text{Ruby} Ruby 语言 Active Record \text{Active Record} Active Record 为标准化实现范例,该工具设定对象与数据表的映射命名约束。
- 单个程序类对应单张数据表,类名采用单数格式且首字母大写,数据表名称采用全小写复数格式。例:数据表 books \text{books} books 对应程序类 Book \text{Book} Book
- 不规则复数词汇遵循英文惯用命名规则。例:数据表 mice \text{mice} mice 对应程序类 Mouse \text{Mouse} Mouse,数据表 people \text{people} people 对应程序类 Person \text{Person} Person
- 多词汇组合名称,程序类采用大驼峰命名格式,数据表采用下划线分隔小写格式。例:数据表 book_clubs \text{book\_clubs} book_clubs 对应程序类 BookClub \text{BookClub} BookClub
- 所有数据表配置主键字段,常规字段名称设定为 id \text{id} id,字段数据类型为整型。外键命名格式为单数表名下划线拼接主键标识,例: item_id \text{item\_id} item_id 关联 items \text{items} items 数据表的 id \text{id} id 字段
三、演示项目环境
本次采用 OpenRecord \text{OpenRecord} OpenRecord 工具库开展实操演示,该工具移植 Active Record \text{Active Record} Active Record 设计逻辑适配 JavaScript \text{JavaScript} JavaScript 语言,整体架构轻量化,入门难度较低。
克隆示例项目至本地设备
bash
$ git clone https://github.com/ruanyf/openrecord-demos.git
进入项目目录并安装依赖组件
javascript
$ cd openrecord-demos
$ npm install
项目内置数据库取自公开范例 SQLite \text{SQLite} SQLite 数据库,数据表结构示意图如下:

结构大图下载地址:http://www.sqlitetutorial.net/wp-content/uploads/2018/03/sqlite-sample-database-diagram-color.pdf
四、数据库连接配置
使用 ORM \text{ORM} ORM 工具的初始步骤为配置数据库连接参数,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo01.js
javascript
// demo01.js
const Store = require('openrecord/store/sqlite3');
const store = new Store({
type: 'sqlite3',
file: './db/sample.db',
autoLoad: true,
});
await store.connect();
连接建立完成后,即可执行数据库交互操作。
五、数据模型 Model
5.1 模型创建
数据库连通后,将数据表映射为程序类结构,该结构定义为数据模型。基础模型编写示例,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo02.js
javascript
// demo02.js
class Customer extends Store.BaseModel {
}
store.Model(Customer);
代码定义 Customer \text{Customer} Customer 类,工具自动匹配同名复数格式数据表 customers \text{customers} customers,调用类结构即可检索数据表数据。
javascript
// demo02.js
const customer = await Customer.find(1);
console.log(customer.FirstName, customer.LastName);
find() \text{find()} find() 方法依据主键检索单条数据记录,查询结果自动转换为对象实例,对象属性与数据表字段一一对应。
5.2 模型属性定义
模型内部可补充数据表字段约束,同时自定义业务处理方法,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo03.js
javascript
// demo03.js
class Customer extends Store.BaseModel {
static definition(){
this.attribute('CustomerId', 'integer', { primary: true });
this.attribute('FirstName', 'string');
this.attribute('LastName', 'string');
this.validatesPresenceOf('FirstName', 'LastName');
}
getFullName(){
return this.FirstName + ' ' + this.LastName;
}
}
代码设定 CustomerId \text{CustomerId} CustomerId 为主键字段,限定名字字段数据类型,约束字段非空,并封装姓名拼接处理方法。实例对象可直接调用自定义方法。
javascript
// demo03.js
const customer = await Customer.find(1);
console.log(customer.getFullName());
六、增删改查 CRUD 操作
数据库基础操作分为新建、读取、更新、删除四类,简称为 CRUD \text{CRUD} CRUD。 ORM \text{ORM} ORM 将四类操作封装为对象内置方法。
6.1 数据查询
find() \text{find()} find() 方法依据主键检索数据,可获取单条或多条记录。
单条记录查询,参考代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo02.js
多条记录查询,参考代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo04.js
javascript
// 返回单条记录
// demo02.js
Customer.find(1)
// 返回多条记录
// demo05.js
Customer.find([1, 2, 3])
where() \text{where()} where() 方法配置筛选条件,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo04.js
javascript
// demo04.js
Customer.where({Company: 'Apple Inc.'}).first()
直接调用模型类可读取数据表全部记录, limit(limit[, offset]) \text{limit(limit[, offset])} limit(limit[, offset]) 方法限定数据读取条数与起始位置,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo06.js
javascript
// demo06.js
const customers = await Customer.limit(5, 10);
示例代码从第 10 条记录位置开始,连续读取 5 条数据。
6.2 数据新建
create() \text{create()} create() 方法完成数据表数据新增,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo12.js
javascript
// demo12.js
Customer.create({
Email: 'president@whitehouse.gov',
FirstName: 'Donald',
LastName: 'Trump',
Address: 'Whitehouse, Washington'
})
6.3 数据更新
update() \text{update()} update() 方法修改已有记录字段数值,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo13.js
javascript
// demo13.js
const customer = await Customer.find(60);
await customer.update({
Address: 'Whitehouse'
});
6.4 数据删除
destroy() \text{destroy()} destroy() 方法移除数据表指定记录,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo14.js
javascript
// demo14.js
const customer = await Customer.find(60);
await customer.destroy();
七、数据表关联关系
7.1 关系分类
数据表之间存在三类关联形式
- 一对一:两类实体实例唯一对应匹配
- 一对多:单个实体实例可关联多个异类实体实例
- 多对多:两类实体互相满足一对多匹配规则
7.2 一对一关联配置
两类模型相互绑定即可构建一对一关联,以顾客与票据数据为例,单个顾客对应单张票据。
在顾客模型内部调用 hasOne() \text{hasOne()} hasOne() 绑定关联模型:
javascript
class Customer extends Store.BaseModel {
static definition(){
this.hasOne('invoices', {model: 'Invoice', from: 'CustomerId', to: 'CustomerId'});
}
}
票据模型内部调用 belongsTo() \text{belongsTo()} belongsTo() 响应关联配置:
javascript
class Invoice extends Store.BaseModel {
static definition(){
this.belongsTo('customer', {model: 'Customer', from: 'CustomerId', to: 'CustomerId'});
}
}
检索数据时借助 include() \text{include()} include() 加载关联模型数据:
javascript
const invoice = await Invoice.find(1).include('customer');
const customer = await invoice.customer;
console.log(customer.getFullName());
7.3 一对多关联配置
实际业务中单个顾客可生成多张票据,属于一对多关联结构。配置逻辑与一对一基本一致,仅将 hasOne() \text{hasOne()} hasOne() 替换为 hasMany() \text{hasMany()} hasMany(),参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo08.js
javascript
// demo08.js
class Customer extends Store.BaseModel {
static definition(){
this.hasMany('invoices', {model: 'Invoice', from: 'CustomerId', to: 'CustomerId'});
}
}
class Invoice extends Store.BaseModel {
static definition(){
this.belongsTo('customer', {model: 'Customer', from: 'CustomerId', to: 'CustomerId'});
}
}
7.4 多对多关联配置
多对多关联依托中间数据表存储实体匹配关系,单曲与歌单为典型多对多场景,需定义三类模型结构,参考完整代码:https://github.com/ruanyf/openrecord-demos/blob/master/demos/demo10.js
javascript
// demo10.js
class Track extends Store.BaseModel{
static definition() {
this.hasMany('track_playlists', { model: 'PlaylistTrack', from: 'TrackId', to: 'TrackId'});
this.hasMany('playlists', { model: 'Playlist', through: 'track_playlists' });
}
}
class Playlist extends Store.BaseModel{
static definition(){
this.hasMany('playlist_tracks', { model: 'PlaylistTrack', from: 'PlaylistId', to: 'PlaylistId' });
this.hasMany('tracks', { model : 'Track', through: 'playlist_tracks' });
}
}
class PlaylistTrack extends Store.BaseModel{
static definition(){
this.tableName = 'playlist_track';
this.belongsTo('playlists', { model: 'Playlist', from: 'PlaylistId', to: 'PlaylistId'});
this.belongsTo('tracks', { model: 'Track', from: 'TrackId', to: 'TrackId'});
}
}
数据检索过程无需主动操作中间表,框架自动完成关联匹配:
javascript
// demo10.js
const track = await Track.find(1).include('playlists');
const playlists = await track.playlists;
playlists.forEach(l => console.log(l.PlaylistId));
单条单曲可匹配多个歌单,查询结果以数组形式返回。
ORM 框架详解:为什么不直接写 SQL
数据小羊 2024-09-15 21:38:50
开发线上图书商城项目,需要存储书籍、用户、订单三类数据。掌握 SQL \text{SQL} SQL 语句的开发人员常会产生疑问,原生 SQL \text{SQL} SQL 语法直观易懂,项目开发过程引入 ORM \text{ORM} ORM 框架的实际意义可通过技术特性与实操案例展开分析。
一、什么是 ORM 框架
ORM \text{ORM} ORM 为 Object-Relational Mapping 的缩写,中文释义为对象关系映射。该技术体系可充当编程语言与关系型数据库的转换媒介。
框架具备四类基础映射能力:
- 依托面向对象语法编写数据库操作逻辑
- 将数据表结构转换为编程语言类结构
- 将表格行数据转换为类实例对象
- 将表格字段转换为对象属性成员
开发人员沿用面向对象编程思维即可完成数据交互,无需编写原生 SQL \text{SQL} SQL 语句。

二、为什么需要 ORM 框架
直接编写 SQL \text{SQL} SQL 语句开展开发工作,会存在多项客观问题:
- 编程范式存在差异,编程语言多为命令式逻辑, SQL \text{SQL} SQL 属于声明式语法,混合编码易造成逻辑割裂
- 常规增删改查操作会产生大量重复代码片段
- 字符串拼接形式编写语句,易引发 SQL \text{SQL} SQL 注入类安全问题
- 代码与特定数据库绑定,切换存储设备需要大规模改写语句
- 查询结果手动转换为程序对象,额外增加编码工作量
ORM \text{ORM} ORM 框架增设抽象交互层级,统一编码范式,缩减代码体量,降低异常出现概率,优化代码维护条件。

三、ORM 与原生 SQL 实操对比
以图书商城根据作者名称检索书籍并调整售价的功能为例,对比两类编码方式。
3.1 原生 SQL 实现
python
import mysql.connector
# 建立数据库连接
conn = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="bookstore"
)
cursor = conn.cursor()
# 条件检索书籍数据
author_name = "J.K. Rowling"
query = "SELECT id, title, price FROM books WHERE author = %s"
cursor.execute(query, (author_name,))
books = cursor.fetchall()
# 批量调整书籍售价
for book in books:
book_id, title, current_price = book
new_price = current_price * 1.1
update_query = "UPDATE books SET price = %s WHERE id = %s"
cursor.execute(update_query, (new_price, book_id))
print(f"Updated price for '{title}' from {current_price} to {new_price}")
# 事务提交与资源释放
conn.commit()
cursor.close()
conn.close()
3.2 SQLAlchemy 框架 ORM 实现
python
from sqlalchemy import create_engine, Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# 初始化数据库引擎
engine = create_engine('mysql://yourusername:yourpassword@localhost/bookstore')
Base = declarative_base()
# 定义书籍数据模型
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(100))
author = Column(String(50))
price = Column(Float)
# 创建数据会话
Session = sessionmaker(bind=engine)
session = Session()
# 检索数据并调整售价
author_name = "J.K. Rowling"
books = session.query(Book).filter_by(author=author_name).all()
for book in books:
book.price *= 1.1
print(f"Updated price for '{book.title}' from {book.price/1.1:.2f} to {book.price:.2f}")
# 提交事务并关闭会话
session.commit()
session.close()
对比结论
- 代码行文更为精简,无需手动编写结构化查询语句
- 数据操作依托对象实例完成,契合面向对象设计规范
- 框架自动处理参数校验,规避注入类安全隐患
- 代码语义贴合业务描述,阅读理解难度更低
- 更换数据库设备仅修改连接配置,语句无需批量调整
四、ORM 技术优势
-
开发效率提升
底层连接管理、语句生成等通用逻辑自动处理,减少模板化代码编写,缩短数据模型搭建与基础操作开发周期。
-
适配面向对象设计
数据操作逻辑与主流编程范式保持统一,可复用继承、多态等语言特性拓展模型结构。
-
代码维护便捷
数据模型统一归档定义,迭代修改定位清晰,通用操作逻辑统一封装,减少冗余代码。
-
跨数据库适配
框架兼容多款数据库产品,切换存储介质仅调整配置参数,对外调用接口格式保持一致。
-
运行安全性提升
默认采用参数化查询模式,降低注入攻击风险,配套数据校验机制,规范入库数据格式。
-
运行性能优化
支持延迟加载机制,按需调取数据内容,部分框架搭载查询缓存功能,重复检索场景可缩减响应耗时。
-
版本迭代管控
配备数据库结构迁移工具,适配数据表字段调整场景,模型代码可纳入版本控制系统统一管理。
-
单元测试适配
支持模拟数据库运行环境,可依托内存数据库完成功能校验,简化测试流程。
五、ORM 技术局限
-
资源消耗增加
层级封装会额外占用系统运算资源,复杂场景自动生成的执行语句优化程度不及手动编写语句。
-
上手存在门槛
框架专属概念与调用接口需要学习掌握,部分框架参数配置流程具备一定复杂度。
-
封装存在边界
特殊复杂查询逻辑无法依托框架语法实现,部分数据库独有功能无法通过封装接口调用。
-
不合理调用易引发异常
查询层级配置不当会产生冗余查询请求,单次调用加载无关数据会造成资源浪费。
-
故障排查难度上升
语句动态生成无法直接查看,复杂逻辑报错提示信息辨识度偏低。
-
版本兼容存在风险
框架版本迭代可能变更调用规则,数据库驱动程序版本也会产生适配约束。
常规业务场景下框架综合价值更高,开发过程结合场景特性权衡技术选型即可。
六、主流 ORM 框架汇总
不同编程语言生态内具备多款成熟框架,常用工具分类如下:
-
Python
SQLAlchemy \text{SQLAlchemy} SQLAlchemy、 Django ORM \text{Django ORM} Django ORM、 Peewee \text{Peewee} Peewee -
Java
Hibernate \text{Hibernate} Hibernate、 JPA \text{JPA} JPA、 MyBatis \text{MyBatis} MyBatis -
C#/.NET
Entity Framework \text{Entity Framework} Entity Framework、 NHibernate \text{NHibernate} NHibernate、 Dapper \text{Dapper} Dapper -
Ruby
Active Record \text{Active Record} Active Record、 Sequel \text{Sequel} Sequel -
JavaScript/Node.js
Sequelize \text{Sequelize} Sequelize、 TypeORM \text{TypeORM} TypeORM、 Mongoose \text{Mongoose} Mongoose -
PHP
Doctrine \text{Doctrine} Doctrine、 Eloquent \text{Eloquent} Eloquent
各类框架功能侧重各不相同,选型结合项目场景、开发团队使用习惯判定即可。
七、框架选型参考依据
- 匹配项目开发所用编程语言,适配技术生态体系
- 评估团队学习成本,参考框架文档完善度与社区交流规模
- 核验大数据量处理状态下的运行效率,确认缓存优化相关功能
- 核对功能清单,满足复杂查询、事务管控等业务需求
- 确认框架兼容项目选用的数据库产品,跨库项目核验通用适配能力
- 判定框架拓展能力,适配项目后期规模扩容与架构升级
- 参考项目维护频次、代码贡献规模,优先选用持续更新的工具
- 企业级项目可考量商业技术配套服务
- 适配项目内部使用的开发工具,保证协同运行稳定
- 确认单元测试相关配套功能,便于项目质量校验
不存在通用适配所有场景的框架,依照项目实际需求筛选适配工具即可。
八、ORM 线上书店后端实操搭建
借助 Python \text{Python} Python 与 SQLAlchemy \text{SQLAlchemy} SQLAlchemy 搭建简易后端程序,演示模型定义、数据查询、关联绑定基础流程。
安装项目依赖组件
bash
pip install sqlalchemy
业务代码编写
python
from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
# 初始化数据库引擎
engine = create_engine('sqlite:///bookstore.db', echo=True)
Base = declarative_base()
# 定义作者数据模型
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
books = relationship("Book", back_populates="author")
# 定义书籍数据模型
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
title = Column(String(100), nullable=False)
price = Column(Float, nullable=False)
author_id = Column(Integer, ForeignKey('authors.id'))
author = relationship("Author", back_populates="books")
# 依据模型自动创建数据表
Base.metadata.create_all(engine)
# 创建数据交互会话
Session = sessionmaker(bind=engine)
session = Session()
# 录入基础业务数据
author1 = Author(name="J.K. Rowling")
book1 = Book(title="Harry Potter and the Philosopher's Stone", price=19.99, author=author1)
book2 = Book(title="Harry Potter and the Chamber of Secrets", price=21.99, author=author1)
session.add(author1)
session.add_all([book1, book2])
session.commit()
# 遍历查询作者与对应书籍信息
authors = session.query(Author).all()
for author in authors:
print(f"Author: {author.name}")
for book in author.books:
print(f" - {book.title} (${book.price:.2f})")
# 修改书籍售价信息
book_to_update = session.query(Book).filter_by(title="Harry Potter and the Philosopher's Stone").first()
if book_to_update:
book_to_update.price = 24.99
session.commit()
print(f"Updated price of '{book_to_update.title}' to ${book_to_update.price:.2f}")
# 移除指定书籍数据
book_to_delete = session.query(Book).filter_by(title="Harry Potter and the Chamber of Secrets").first()
if book_to_delete:
session.delete(book_to_delete)
session.commit()
print(f"Deleted '{book_to_delete.title}'")
session.close()
示例代码实现模型定义、关联绑定、数据表创建、数据增删改查完整流程,直观体现框架简化数据库操作的特性。
九、总结
ORM \text{ORM} ORM 框架可简化数据库交互逻辑,优化代码编写与维护条件。原生 SQL \text{SQL} SQL 语句在特定场景具备独有优势,两类技术可结合使用。
框架应用具备多项正向作用,能够缩减开发耗时、规整代码结构、兼容多类数据库、降低安全风险,契合面向对象编程设计思路。同时框架存在资源损耗、学习门槛、复杂逻辑适配受限等客观问题。
常规网站程序、企业业务系统均可引入 ORM \text{ORM} ORM 框架开展开发工作。开发人员需要掌握底层数据库运行原理,结合业务场景灵活选用编码方式,复杂检索场景可搭配原生语句协同开发。

reference
- ORM 框架介绍------什么是 ORM 框架? - jiuchengi - 博客园
https://www.cnblogs.com/xiaotian0422/p/16496908.html - ORM 实例教程 - 阮一峰的网络日志
https://www.ruanyifeng.com/blog/2019/02/orm-tutorial.html - ORM 框架详解:为什么不直接写 SQL?_orm 和 sql-CSDN 博客
https://blog.csdn.net/u012955829/article/details/142289384