ORM框架详解:为什么不直接写SQL?

news2024/9/23 21:19:03

想象一下,你正在开发一个小型的在线书店应用。你需要存储书籍信息、用户数据和订单记录。作为一个初学者,你可能会想:“我已经学会了SQL,为什么还要使用ORM框架呢?直接写SQL语句不是更简单、更直接吗?”

如果你有类似的疑问,那么恭喜你!你已经踏上了深入理解数据库交互的journey。在这篇文章中,我们将一起探索ORM框架的世界,了解它为什么存在,以及它如何能够提升你的开发效率和代码质量。
image.png

目录

    • 什么是ORM框架?
    • 为什么需要ORM框架?
    • ORM vs 直接SQL:一个实际例子
      • 直接使用SQL
      • 使用ORM(以SQLAlchemy为例)
    • ORM的优势
    • ORM的潜在缺点
    • 常见的ORM框架
    • 如何选择合适的ORM框架
    • 实际应用:使用ORM构建在线书店后端
    • 结论

什么是ORM框架?

ORM是"Object-Relational Mapping"的缩写,中文通常翻译为"对象关系映射"。这个术语听起来可能有点抽象,让我们通过一个简单的比喻来理解它:

想象你是一位翻译官,你的工作是在两种完全不同的语言之间进行翻译。在编程世界中,ORM就像这样一位翻译官,它在面向对象的编程语言(如Java、Python、C#等)和关系型数据库(如MySQL、PostgreSQL、Oracle等)之间进行"翻译"。

具体来说,ORM框架允许你:

  1. 使用面向对象的方式来操作数据库
  2. 将数据库表映射到编程语言中的类
  3. 将表中的记录映射到类的实例(对象)
  4. 将表的字段映射到对象的属性

通过这种映射,你可以使用熟悉的面向对象编程(OOP)概念和语法来进行数据库操作,而不需要直接编写SQL语句。
image.png

为什么需要ORM框架?

在回答这个问题之前,让我们先思考一下直接使用SQL可能会遇到的一些挑战:

  1. 语言不匹配:SQL是一种声明式语言,而大多数编程语言是命令式的。这种范式的差异可能导致代码的不一致性和复杂性。

  2. 代码重复:对于常见的CRUD(创建、读取、更新、删除)操作,你可能会发现自己在不同的地方重复编写相似的SQL语句。

  3. 安全性问题:直接拼接SQL字符串容易导致SQL注入攻击,需要额外的注意和处理。

  4. 数据库依赖:直接编写SQL会使你的代码与特定的数据库系统紧密耦合,难以切换到其他数据库。

  5. 面向对象的不匹配:在面向对象的程序中,你需要手动将SQL查询结果转换为对象,这个过程可能很繁琐。
    image.png

ORM框架的出现就是为了解决这些问题。它提供了一个抽象层,使得开发者可以用面向对象的方式来操作数据库,从而提高开发效率,减少错误,并使代码更易于维护。

ORM vs 直接SQL:一个实际例子

让我们通过一个具体的例子来比较使用ORM和直接写SQL的区别。假设我们要实现earlier提到的在线书店应用中的一个功能:根据作者名称查询书籍并更新价格。
image.png

直接使用SQL

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  # 提高10%的价格
    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()

使用ORM(以SQLAlchemy为例)

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

# 定义Book模型
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  # 提高10%的价格
    print(f"Updated price for '{book.title}' from {book.price/1.1:.2f} to {book.price:.2f}")

# 提交事务
session.commit()
session.close()

通过比较这两段代码,我们可以看到使用ORM带来的一些明显优势:

  1. 代码简洁性:ORM版本的代码更加简洁,不需要手动编写SQL语句。

  2. 面向对象的操作:在ORM版本中,我们直接操作Book对象,这与面向对象编程的思想更加一致。

  3. 安全性:ORM自动处理参数化查询,减少SQL注入的风险。

  4. 可读性:ORM代码更接近自然语言描述,更容易理解代码的意图。

  5. 数据库无关性:如果需要切换到不同的数据库系统,只需要更改连接字符串,而不需要重写SQL语句。

ORM的优势

image.png

通过上面的例子,我们已经看到了ORM的一些优点。让我们更系统地总结一下ORM框架的主要优势:

  1. 生产力提升

    • 减少样板代码:ORM自动处理了许多底层的数据库操作,如连接管理、SQL生成等。
    • 快速开发:使用ORM可以更快地构建数据模型和执行常见的数据库操作。
  2. 面向对象的优雅

    • 自然的编程模型:ORM允许你用面向对象的方式思考和操作数据,这与大多数现代编程语言的范式一致。
    • 继承和多态:可以利用面向对象的特性来设计更灵活、可扩展的数据模型。
  3. 可维护性

    • 集中的数据模型定义:数据模型通常定义在一个地方,便于管理和修改。
    • 减少重复代码:常见的数据库操作被抽象化,减少了代码重复。
  4. 数据库无关性

    • 易于切换数据库:大多数ORM支持多种数据库后端,切换数据库只需要更改配置。
    • 跨数据库的一致API:无论底层使用什么数据库,你都可以使用相同的API进行操作。
  5. 安全性

    • 参数化查询:ORM自动使用参数化查询,大大降低SQL注入的风险。
    • 数据验证:许多ORM框架提供了数据验证功能,可以在数据进入数据库之前进行检查。
  6. 性能优化

    • 延迟加载:ORM可以智能地决定何时从数据库加载数据,避免不必要的查询。
    • 缓存:一些ORM框架提供查询缓存功能,可以提高反复查询的性能。
  7. 版本控制和迁移

    • 数据库迁移:许多ORM框架提供了数据库迁移工具,使得管理数据库schema的变更变得更加容易。
    • 版本控制:数据模型可以像其他代码一样进行版本控制。
  8. 测试友好

    • 易于模拟:使用ORM,你可以更容易地模拟数据库操作,便于单元测试。
    • 内存数据库:许多ORM支持内存数据库,可以加速测试过程。

ORM的潜在缺点

尽管ORM框架带来了许多优势,但它也不是没有缺点。了解这些潜在的问题对于正确使用ORM非常重要:

  1. 性能开销

    • 额外的抽象层:ORM在应用程序和数据库之间增加了一个抽象层,这可能导致一些性能开销。
    • 可能生成次优的SQL:在复杂查询场景下,ORM生成的SQL可能不如手写的SQL优化。
  2. 学习曲线

    • 新的概念:使用ORM需要学习新的概念和API,对于初学者来说可能有一定难度。
    • 配置复杂性:某些ORM框架的配置可能比较复杂,需要时间来掌握。
  3. "漏抽象"问题

    • 无法完全隐藏SQL:在某些复杂查询场景下,你可能还是需要编写原生SQL或了解底层的SQL知识。
    • 特定数据库功能:某些数据库特有的高级功能可能无法通过ORM直接使用。
  4. 过度使用的风险

    • N+1查询问题:如果不小心,很容易导致N+1查询问题,影响性能。
    • 加载过多数据:如果不正确使用,可能会从数据库加载不必要的数据。
  5. 调试困难

    • SQL不可见:由于SQL是动态生成的,调试复杂查询可能会变得困难。
    • 错误信息不清晰:ORM的错误信息有时可能不如直接的SQL错误信息清晰。
  6. 版本兼容性

    • ORM更新可能带来不兼容:ORM框架的主要版本更新可能需要修改现有代码。
    • 数据库驱动兼容性:ORM可能对特定版本的数据库驱动有依赖。
      image.png

尽管存在这些潜在的缺点,但对于大多数应用程序来说,ORM的优势仍然远大于缺点。关键是要理解这些限制,并在适当的时候做出权衡。

常见的ORM框架

不同的编程语言通常有其流行的ORM框架。以下是一些主流编程语言中常用的ORM框架:

  1. Python

    • SQLAlchemy:功能强大、灵活性高的ORM框架
    • Django ORM:Django web框架自带的ORM
    • Peewee:轻量级、简单易用的ORM
  2. Java

    • Hibernate:最流行的Java ORM框架之一
    • JPA (Java Persistence API):Java EE的ORM标准
    • MyBatis:一种"半自动"的ORM框架
  3. C#/.NET

    • Entity Framework:微软官方的ORM框架
    • NHibernate:Hibernate的.NET移植版
    • Dapper:一个轻量级的ORM框架
  4. Ruby

    • Active Record:Ruby on Rails框架中使用的ORM
    • Sequel:一个独立的Ruby ORM
  5. JavaScript/Node.js

    • Sequelize:支持多种数据库的ORM
    • TypeORM:支持TypeScript的ORM
    • Mongoose:专门用于MongoDB的ODM(对象文档映射)
  6. PHP

    • Doctrine:受Hibernate启发的PHP ORM
    • Eloquent:Laravel框架中使用的ORM
      image.png

每个框架都每个框架都有其独特的特性和优势,选择哪一个通常取决于你的具体需求、项目规模、以及个人或团队的偏好。

如何选择合适的ORM框架

选择合适的ORM框架对于项目的成功至关重要。以下是一些选择ORM框架时需要考虑的因素:

  1. 语言和生态系统兼容性

    • 确保ORM框架与你的主要编程语言有良好的集成。
    • 考虑框架在该语言生态系统中的地位和受欢迎程度。
  2. 学习曲线

    • 评估你和你的团队学习新框架所需的时间。
    • 考虑框架的文档质量和社区支持。
  3. 性能

    • 研究框架在处理大量数据时的性能表现。
    • 考虑框架是否提供性能优化工具,如缓存机制。
  4. 功能集

    • 确保框架支持你需要的所有数据库操作。
    • 检查是否支持高级功能,如复杂查询、事务管理等。
  5. 数据库支持

    • 确保框架支持你计划使用的数据库系统。
    • 如果你需要支持多个数据库,检查框架的跨数据库能力。
  6. 可扩展性

    • 考虑框架是否能够随着项目的增长而扩展。
    • 检查是否支持分布式系统或微服务架构。
  7. 社区和维护

    • 查看框架的GitHub星数、贡献者数量等指标。
    • 检查最近的更新频率,确保框架仍在积极维护。
  8. 企业支持

    • 如果是企业级项目,考虑是否有商业支持选项。
  9. 与其他工具的集成

    • 检查框架是否能与你使用的其他开发工具良好集成。
  10. 测试支持

    • 考虑框架是否提供良好的测试支持,如易于模拟的API。
      image.png

通过仔细权衡这些因素,你可以为你的项目选择最合适的ORM框架。记住,没有一个框架是完美的或适合所有场景的,关键是找到最适合你特定需求的解决方案。

实际应用:使用ORM构建在线书店后端

为了更好地理解ORM在实际项目中的应用,让我们用Python和SQLAlchemy来构建一个简单的在线书店后端。这个例子将展示如何定义模型、执行查询、以及处理关系。

首先,我们需要安装必要的依赖:

pip install sqlalchemy

然后,我们可以开始编写我们的代码:

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

这个例子展示了如何:

  1. 定义数据模型(Author和Book)
  2. 建立模型之间的关系
  3. 创建数据库表
  4. 添加、查询、更新和删除数据

通过这个简单的例子,我们可以看到ORM如何简化数据库操作,使得代码更加直观和面向对象。

结论

ORM框架为开发者提供了一种强大的工具,使得数据库操作变得更加简单、直观和安全。虽然直接编写SQL在某些情况下可能更简单或更高效,但ORM带来的好处通常超过了其潜在的缺点。

ORM的主要优势包括:

  • 提高开发效率
  • 增强代码的可维护性
  • 提供数据库无关性
  • 增强应用程序的安全性
  • 允许利用面向对象编程的优势

然而,使用ORM也需要权衡一些因素:

  • 可能带来一定的性能开销
  • 存在学习曲线
  • 在某些复杂查询场景可能不如直接SQL灵活

对于大多数现代web应用程序和企业系统来说,ORM已经成为了标准工具。它不仅简化了开发过程,还提高了代码质量和可维护性。然而,像所有工具一样,ORM也不是万能的。理解ORM的工作原理、优势和局限性,才能在适当的场景下做出正确的选择。

最后,记住:ORM和SQL并不是非此即彼的选择。在实际项目中,你可能会发现将ORM与原生SQL结合使用是最佳实践。大多数ORM框架都提供了执行原生SQL的能力,让你能够在需要时利用SQL的全部功能。
image.png

无论你选择使用ORM还是直接编写SQL,重要的是要理解底层的数据库原理,这样你才能做出明智的决策,并在需要时进行优化。持续学习和实践将帮助你在不同场景下选择最合适的工具和方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2138772.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CS110L】Rust语言 Lecture3-4 笔记

文章目录 第三讲 所有权:移动与借用&例1例2例3 错误处理(开头)为什么空指针如此危险,我们能做什么以应对?— 引出Optionis_none()函数unwrap_or()函数常见用法 第四讲 代码实践:链表Box节点和链表的定义节点和链表的构造函数判…

基于Sobel算法的边缘检测设计与实现

1、边缘检测 针对的时灰度图像,顾名思义,检测图像的边缘,是针对图像像素点的一种计算,目的时标识数字图像中灰度变化明显的点,图像的边缘检测,在保留了图像的重要结构信息的同时,剔除了可以认为…

【WPF】桌面程序开发之xaml页面绑定数据模型详解

使用Visual Studio开发工具,我们可以编写在Windows系统上运行的桌面应用程序。其中,WPF(Windows Presentation Foundation)项目是一种常见的选择。然而,对于初学者来说,WPF项目中xaml页面的布局设计可能是一…

unity3d入门教程七

unity3d入门教程七 17.1物理系统17.2静态刚体17.3刚体的碰撞17.4刚体的反弹18.1运动学刚体18.2碰撞检测18.3碰撞事件回调18.4目标的识别18.5碰撞的规避 17.1物理系统 在物理系统中的物体具有质量和速度的是刚体 不用写代码就会自由落体运动了 17.2静态刚体 给 ‘地面’ 添…

conda安装qgis(亲测没问题)

conda安装qgis(亲测没问题,目前测试win10,linux其实也是可以的) 目录 1.前提 2.准备条件 3.实战 4.扩展 1.前提 意外发现conda可以安装qgis,即使不是完全版,但是矢量空间分析都可以用,那么…

影刀RPA实战:网页爬虫之CSDN博文作品数据

今天我们使用影刀来采集网页数据,影刀RPA是一款功能强大的自动化办公软件,它可以模拟人工的各种操作,帮助企业自动处理大量重复性、有逻辑规则的工作。影刀RPA在网页数据采集方面表现出色,能够实现对任何桌面软件、Web程序的自动化…

危机中的机遇:客户服务在品牌危机管理中的角色与价值

在瞬息万变的商业环境中,品牌危机如同暗流涌动的漩涡,随时可能将企业卷入深渊。然而,正如古语所云:“祸兮福之所倚”,危机之中往往也蕴藏着转机与机遇。在这一过程中,客户服务作为企业与消费者之间的桥梁&a…

物品识别——基于python语言

目录 1.物品识别 2.模型介绍 3.文件框架 4.代码示例 4.1 camera.py 4.2 interaction.py 4.3 object_detection.py 4.4 main.py 4.5 运行结果 5.总结 1.物品识别 该项目使用Python,OpenCV进行图像捕捉,进行物品识别。我们将使用YOLO&#xff08…

Dating App约会软件都有哪些商业化策略

在设计一个成功的Dating App时,吸引并留住用户(特别是女用户)和实现商业化是两个核心任务。比如探探、陌陌等,以下是可行的产品流程思路,以及商业化的功能设计策略,借鉴了成熟的约会平台的经验。 吸引并留住…

2000-2021年3月海关数据库

2000-2021年3月海关数据库 1、时间:2000-2021年3月 2、指标:2000-2015数据变量包括:年份、截止日期、进出口分类代码、进出口分类名称、HS商品编码、HS商品名称、金额_美元、数量、价格、经营单位代码、经营单位名称、经营单位地址、电话、…

AI论文写作测评!类似茅茅虫论文写作助手网站

在当前的学术研究和写作环境中,AI论文写作助手成为了许多学者和学生的重要工具。其中,千笔-AIPassPaper和茅茅虫论文写作助手是两款备受关注的平台。本文将对这两款工具进行详细测评,并推荐适合不同需求的用户使用。 千笔-AIPassPaper AI论文…

linux安全软件Hydra使用教程

Hydra 是一个强大的网络登录工具,常用于渗透测试,支持对多种服务和协议(如 SSH、FTP、HTTP 等)进行暴力crack攻击。它可以通过字典攻击来测试用户名和密码的有效性。以下是关于如何使用 Hydra 的基本步骤和示例: 1. 安…

【mechine learning-九-梯度下降】

梯度下降 更加通用的梯度下降算法算法步骤 上一节讲过,随机的寻找w和b使损失最小不是一种合适的方法,梯度下降算法就是解决解决这个问题的,它不仅可以用于线性回归,还可以用于神经网络等深度学习算法,是目前的通用性算…

【QT】定时器使用

文章目录 关于 Qt 定时器使用的注意细节总结实例-检查工具使用周期时间是否合理UI设计头文件 remind.h源文件 remind.cpp实现效果 关于 Qt 定时器使用的注意细节总结 一、创建与初始化 使用 QTimer 类来创建定时器。可以在构造函数中指定父对象,确保定时器在正确的…

跨境电商代购新纪元:一键解锁全球好物,系统流程全揭秘

添加图片注释,不超过 140 字(可选) 在全球化日益加深的今天,跨境电商代购成为了连接消费者与世界各地优质商品的桥梁。本文将在CSDN平台上,深入剖析跨境电商代购系统的功能流程,带您一窥其背后的技术奥秘与…

vue3+ant design vue实现可编辑表格弹出气泡弹出窗~

1、这里主要是介绍下::v-deep伪元素的作用。用于穿透组件作用域&#xff0c;以便在组件内部修改样式。用来覆盖Ant Design Vue组件库中的样式 <a-table:dataSource"dataList":columns"columns":scroll"{ x: 100% }":pagination"false&q…

架构师备考的一些思考(四)

前言 对于数学&#xff0c;我们之前学的是对的&#xff0c;但不是真的&#xff0c;所以我们没有数学思维。 对于计算机&#xff0c;我们学校教的是对的&#xff0c;但不是真的&#xff0c;所以仅仅从学校学习知识的应届毕业生&#xff0c;不论985,211&#xff0c;本科&#xff…

优化深度学习模型训练过程:提升PASCAL VOC 2012数据集上Deeplabv3+模型训练效率的策略

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 优化说明&#xff1a; 避免重复下载和解压数据集&#xff1a;将downloadTrue改为downloadFalse&#xff0c;防止每次运行代码都重新下载和解压数据集&#xff0c;从而节省时间。 使用pin…

8. Transforms的使用(三)-- Resize

Transforms的使用(三) 1. 为什么要使用Resize 在模型的训练过程中往往需要图片数据的维度相同,才能适应深度学习模型中的相关神经网络结构,这时候就需要使用Resize保证所有的图片保持相同的尺寸2. 使用Resize调整图片的尺寸 在pytorch2.3的版本上,Resize()支持对Tensor类…

k8s Service 服务

文章目录 一、为什么需要 Service二、Kubernetes 中的服务发现与负载均衡 -- Service三、用例解读1、Service 语法2、创建和查看 Service 四、Headless Service五、集群内访问 Service六、向集群外暴露 Service七、操作示例1、获取集群状态信息2、创建 Service、Deployment3、创…