ORM | 框架原理、实操与应用选型

注:本文为 "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 框架包含五类:

  1. Hibernate \text{Hibernate} Hibernate:全自动映射框架,业务逻辑编写依托 HQL \text{HQL} HQL 语句
  2. iBATIS \text{iBATIS} iBATIS:半自动映射框架,支持自定义编写 SQL \text{SQL} SQL 语句,具备灵活操控性,程序体量轻便
  3. MyBatis \text{MyBatis} MyBatis
  4. EclipseLink \text{EclipseLink} EclipseLink
  5. JFinal \text{JFinal} JFinal

2 技术应用价值

未引入 ORM \text{ORM} ORM 机制的应用程序,数据访问层会存在大量同质化代码,数据新增、删除、读取等基础操作均需要重复编写对应逻辑。

引入 ORM \text{ORM} ORM 机制能够缩减重复代码体量,该技术体系可完成程序对象与关系型数据库数据之间的映射转换。

3 对象-关系映射特性

  1. 结构简约
    ORM \text{ORM} ORM 依照基础逻辑完成数据建模,可将 MySQL \text{MySQL} MySQL 数据表映射为编程语言类结构,数据表字段对应类内部成员变量。

  2. 映射标准统一

    所有 MySQL \text{MySQL} MySQL 数据表按照固定规则转换为程序类结构,程序代码层级的数据格式可保持统一规范。

  3. 结构可读性良好

    数据库存储结构可通过映射关系转换为程序代码结构,开发人员可依托编程语言逻辑理解数据库架构。

  4. 操作接口完备

    框架封装持久化对象的增删改查接口,包含 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 正向特性

  1. 缩减项目开发周期,控制开发投入成本
  2. 代码编写逻辑贴合面向对象设计思想
  3. 具备跨数据库运行适配能力
  4. 可便捷拓展数据缓存类附属功能

4.2 反向特性

  1. 自动映射流程会占用设备运算资源,常规业务场景下资源消耗处于可接受范围
  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 应用优势

  1. 数据模型集中定义,便于迭代调整与复用开发
  2. 配套工具可自动完成数据清洗、预处理、事务管控等流程
  3. 适配 MVC \text{MVC} MVC 架构设计,模型层级划分清晰,代码结构规整
  4. 业务代码语句简洁,语义直观,便于代码阅读
  5. 规避低效 SQL \text{SQL} SQL 语句编写问题

ORM 应用局限

  1. 框架体量偏大,框架学习与参数配置需要投入时间
  2. 复杂检索场景下,部分逻辑无法通过 ORM \text{ORM} ORM 语法实现,执行效率不及原生 SQL \text{SQL} SQL
  3. 底层数据库运行逻辑被封装屏蔽,定制化特殊语句编写存在限制

二、命名规范

各类编程语言均配套专属 ORM \text{ORM} ORM 工具库, Ruby \text{Ruby} Ruby 语言 Active Record \text{Active Record} Active Record 为标准化实现范例,该工具设定对象与数据表的映射命名约束。

  1. 单个程序类对应单张数据表,类名采用单数格式且首字母大写,数据表名称采用全小写复数格式。例:数据表 books \text{books} books 对应程序类 Book \text{Book} Book
  2. 不规则复数词汇遵循英文惯用命名规则。例:数据表 mice \text{mice} mice 对应程序类 Mouse \text{Mouse} Mouse,数据表 people \text{people} people 对应程序类 Person \text{Person} Person
  3. 多词汇组合名称,程序类采用大驼峰命名格式,数据表采用下划线分隔小写格式。例:数据表 book_clubs \text{book\_clubs} book_clubs 对应程序类 BookClub \text{BookClub} BookClub
  4. 所有数据表配置主键字段,常规字段名称设定为 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 关系分类

数据表之间存在三类关联形式

  1. 一对一:两类实体实例唯一对应匹配
  2. 一对多:单个实体实例可关联多个异类实体实例
  3. 多对多:两类实体互相满足一对多匹配规则

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 的缩写,中文释义为对象关系映射。该技术体系可充当编程语言与关系型数据库的转换媒介。

框架具备四类基础映射能力:

  1. 依托面向对象语法编写数据库操作逻辑
  2. 将数据表结构转换为编程语言类结构
  3. 将表格行数据转换为类实例对象
  4. 将表格字段转换为对象属性成员

开发人员沿用面向对象编程思维即可完成数据交互,无需编写原生 SQL \text{SQL} SQL 语句。

二、为什么需要 ORM 框架

直接编写 SQL \text{SQL} SQL 语句开展开发工作,会存在多项客观问题:

  1. 编程范式存在差异,编程语言多为命令式逻辑, SQL \text{SQL} SQL 属于声明式语法,混合编码易造成逻辑割裂
  2. 常规增删改查操作会产生大量重复代码片段
  3. 字符串拼接形式编写语句,易引发 SQL \text{SQL} SQL 注入类安全问题
  4. 代码与特定数据库绑定,切换存储设备需要大规模改写语句
  5. 查询结果手动转换为程序对象,额外增加编码工作量

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()

对比结论

  1. 代码行文更为精简,无需手动编写结构化查询语句
  2. 数据操作依托对象实例完成,契合面向对象设计规范
  3. 框架自动处理参数校验,规避注入类安全隐患
  4. 代码语义贴合业务描述,阅读理解难度更低
  5. 更换数据库设备仅修改连接配置,语句无需批量调整

四、ORM 技术优势

  1. 开发效率提升

    底层连接管理、语句生成等通用逻辑自动处理,减少模板化代码编写,缩短数据模型搭建与基础操作开发周期。

  2. 适配面向对象设计

    数据操作逻辑与主流编程范式保持统一,可复用继承、多态等语言特性拓展模型结构。

  3. 代码维护便捷

    数据模型统一归档定义,迭代修改定位清晰,通用操作逻辑统一封装,减少冗余代码。

  4. 跨数据库适配

    框架兼容多款数据库产品,切换存储介质仅调整配置参数,对外调用接口格式保持一致。

  5. 运行安全性提升

    默认采用参数化查询模式,降低注入攻击风险,配套数据校验机制,规范入库数据格式。

  6. 运行性能优化

    支持延迟加载机制,按需调取数据内容,部分框架搭载查询缓存功能,重复检索场景可缩减响应耗时。

  7. 版本迭代管控

    配备数据库结构迁移工具,适配数据表字段调整场景,模型代码可纳入版本控制系统统一管理。

  8. 单元测试适配

    支持模拟数据库运行环境,可依托内存数据库完成功能校验,简化测试流程。

五、ORM 技术局限

  1. 资源消耗增加

    层级封装会额外占用系统运算资源,复杂场景自动生成的执行语句优化程度不及手动编写语句。

  2. 上手存在门槛

    框架专属概念与调用接口需要学习掌握,部分框架参数配置流程具备一定复杂度。

  3. 封装存在边界

    特殊复杂查询逻辑无法依托框架语法实现,部分数据库独有功能无法通过封装接口调用。

  4. 不合理调用易引发异常

    查询层级配置不当会产生冗余查询请求,单次调用加载无关数据会造成资源浪费。

  5. 故障排查难度上升

    语句动态生成无法直接查看,复杂逻辑报错提示信息辨识度偏低。

  6. 版本兼容存在风险

    框架版本迭代可能变更调用规则,数据库驱动程序版本也会产生适配约束。

常规业务场景下框架综合价值更高,开发过程结合场景特性权衡技术选型即可。

六、主流 ORM 框架汇总

不同编程语言生态内具备多款成熟框架,常用工具分类如下:

  1. Python
    SQLAlchemy \text{SQLAlchemy} SQLAlchemy、 Django ORM \text{Django ORM} Django ORM、 Peewee \text{Peewee} Peewee

  2. Java
    Hibernate \text{Hibernate} Hibernate、 JPA \text{JPA} JPA、 MyBatis \text{MyBatis} MyBatis

  3. C#/.NET
    Entity Framework \text{Entity Framework} Entity Framework、 NHibernate \text{NHibernate} NHibernate、 Dapper \text{Dapper} Dapper

  4. Ruby
    Active Record \text{Active Record} Active Record、 Sequel \text{Sequel} Sequel

  5. JavaScript/Node.js
    Sequelize \text{Sequelize} Sequelize、 TypeORM \text{TypeORM} TypeORM、 Mongoose \text{Mongoose} Mongoose

  6. PHP
    Doctrine \text{Doctrine} Doctrine、 Eloquent \text{Eloquent} Eloquent

各类框架功能侧重各不相同,选型结合项目场景、开发团队使用习惯判定即可。

七、框架选型参考依据

  1. 匹配项目开发所用编程语言,适配技术生态体系
  2. 评估团队学习成本,参考框架文档完善度与社区交流规模
  3. 核验大数据量处理状态下的运行效率,确认缓存优化相关功能
  4. 核对功能清单,满足复杂查询、事务管控等业务需求
  5. 确认框架兼容项目选用的数据库产品,跨库项目核验通用适配能力
  6. 判定框架拓展能力,适配项目后期规模扩容与架构升级
  7. 参考项目维护频次、代码贡献规模,优先选用持续更新的工具
  8. 企业级项目可考量商业技术配套服务
  9. 适配项目内部使用的开发工具,保证协同运行稳定
  10. 确认单元测试相关配套功能,便于项目质量校验

不存在通用适配所有场景的框架,依照项目实际需求筛选适配工具即可。

八、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

相关推荐
写了20年代码的老程序员3 天前
写了 20 年 Java,我受够了 MyBatis 的 4 个瞬间
mybatis·orm
rising start9 天前
InsightEdu - 轻量智能学习平台
javascript·axios·css3·html5·fastapi·orm·dify
码农刚子11 天前
.NET 8 Web开发入门(四):注入燃料——Entity Framework Core 与 Code First 实战
数据库·orm·sql server
CSharp精选营11 天前
.NET 8 Web开发入门(四):注入燃料——Entity Framework Core 与 Code First 实战
orm·sql server·数据库迁移·ef core·entity framework core·crud操作·code first
阿kun要赚马内12 天前
后端数据操作组合:Pydantic与ORM
后端·python·orm·sqlalchemy
jump_jump15 天前
Drizzle 凭什么贴着 Go 跑——从设计哲学到热路径源码
数据库·性能优化·orm
L-影17 天前
常见的 ORM 工具
开发语言·数据库·fastapi·orm
李温候17 天前
互联网大厂Java求职者面试全攻略
java·数据库·面试·orm·构建工具·web框架·互联网大厂
L-影17 天前
fastapi中的ORM
数据库·fastapi·orm