pin_drop当前位置:知识文库 ❯ 图文
Python ORM对象关系映射教程 - 优缺点对比与框架推荐
一、什么是ORM
ORM(Object-Relational Mapping,对象关系映射)是一种编程技术,用于在面向对象编程语言和关系型数据库之间建立映射关系。通过ORM,开发者可以使用面向对象的方式操作数据库,而无需编写SQL语句。
ORM的核心思想是将数据库中的表映射为Python类,表中的行映射为类的实例,表中的列映射为类的属性。这样,开发者就可以使用面向对象的方式来操作数据库。
ORM映射关系
二、ORM的优缺点
ORM的优势
-
提高开发效率:无需编写SQL语句,用面向对象的方式操作数据库,代码更简洁
-
数据库无关性:同一套ORM代码可以运行在不同的数据库上,只需切换配置
-
类型安全:IDE可以提供自动补全和类型检查,减少错误
-
安全性:ORM框架自动处理SQL转义,有效防止SQL注入
-
关系映射:轻松处理一对多、多对多等复杂关系
ORM的劣势
-
性能开销:ORM将对象操作转换为SQL,存在额外的性能损耗
-
学习成本:需要学习ORM的API和概念,初期学习曲线较陡
-
复杂查询困难:某些复杂SQL查询用ORM表达困难或效率低下
-
N+1查询问题:不当使用ORM容易产生N+1查询,严重影响性能
三、ORM与原生SQL对比
下面通过具体示例来对比ORM和原生SQL在相同操作下的代码差异:
查询所有用户
代码示例
# 原生SQL方式(使用PyMySQL)
cursor.execute('SELECT id, name, email, age FROM users')
users = cursor.fetchall()
for user in users:
print(f"{user['name']}: {user['email']}")
# ORM方式(使用SQLAlchemy)
users = session.query(User).all()
for user in users:
print(f"{user.name}: {user.email}")条件查询
代码示例
# 原生SQL方式
cursor.execute(
'SELECT * FROM users WHERE age > %s AND status = %s ORDER BY name',
(18, 'active')
)
users = cursor.fetchall()
# ORM方式
users = session.query(User)\
.filter(User.age > 18, User.status == 'active')\
.order_by(User.name)\
.all()插入数据
代码示例
# 原生SQL方式
cursor.execute(
'INSERT INTO users (name, email, age) VALUES (%s, %s, %s)',
('张三', 'zhangsan@example.com', 25)
)
conn.commit()
new_id = cursor.lastrowid
# ORM方式
new_user = User(name='张三', email='zhangsan@example.com', age=25)
session.add(new_user)
session.commit()
new_id = new_user.id关联查询
代码示例
# 原生SQL方式
cursor.execute('''
SELECT u.name, o.product_name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.id = %s
''', (user_id,))
results = cursor.fetchall()
# ORM方式(假设已定义User和Order模型的关系)
user = session.query(User).get(user_id)
for order in user.orders:
print(f"{user.name} 购买了 {order.product_name},金额:{order.amount}")四、Python主流ORM框架
小贴士
SQLAlchemy是Python生态中最流行的独立ORM框架,本系列教程后续将重点介绍SQLAlchemy的使用。如果你想了解Django的ORM,可以参考Django官方文档。
五、ORM核心概念
了解ORM的核心概念是使用ORM框架的前提。以下是ORM中最常见的核心概念:
1. 模型定义(Model)
模型是ORM中最基本的概念,每个模型对应数据库中的一张表。模型通过类定义,类属性对应表的列。
代码示例
# SQLAlchemy模型定义示例
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False)
email = Column(String(100), unique=True, nullable=False)
age = Column(Integer)
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}')>"2. 会话(Session)
会话是ORM与数据库交互的工作空间。所有数据库操作都通过会话进行,会话负责跟踪对象的状态变化。
代码示例
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# 创建引擎
engine = create_engine('sqlite:///example.db')
# 创建会话工厂
Session = sessionmaker(bind=engine)
# 创建会话
session = Session()
# 使用会话操作数据库
new_user = User(name='张三', email='zhangsan@example.com', age=25)
session.add(new_user)
session.commit()
session.close()3. 关系映射(Relationship)
ORM支持定义表之间的关系,包括一对一、一对多、多对多关系。
代码示例
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
# 一对多关系:一个用户可以有多个订单
orders = relationship('Order', back_populates='user')
class Order(Base):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
product_name = Column(String(200))
# 反向关系
user = relationship('User', back_populates='orders')4. 查询构建器(Query Builder)
ORM提供链式查询API,可以构建复杂的数据库查询。
代码示例
# 基本查询
users = session.query(User).all()
# 条件查询
adults = session.query(User).filter(User.age >= 18).all()
# 排序和限制
top_users = session.query(User).order_by(User.name).limit(10).all()
# 聚合查询
from sqlalchemy import func
count = session.query(func.count(User.id)).scalar()
avg_age = session.query(func.avg(User.age)).scalar()
# 关联查询(预加载避免N+1问题)
from sqlalchemy.orm import joinedload
users_with_orders = session.query(User)\
.options(joinedload(User.orders))\
.all()六、注意事项
⚠️ 注意1:N+1查询问题
当查询一个列表并访问每个对象的关联数据时,ORM会执行N+1次查询(1次主查询+N次关联查询)。使用
joinedload或subqueryload预加载关联数据来解决。
⚠️ 注意2:ORM不是万能的
对于简单的CRUD操作,ORM非常方便。但对于复杂的数据分析查询、批量操作或性能敏感场景,直接使用原生SQL可能更高效。ORM框架通常也支持执行原生SQL。
⚠️ 注意3:会话管理
使用完会话后务必调用
session.close(),避免连接泄漏。在Web应用中,建议每个请求创建一个会话,请求结束后自动关闭。
⚠️ 注意4:理解底层SQL
使用ORM不等于可以完全不懂SQL。了解SQL有助于理解ORM生成的查询,排查性能问题。大多数ORM都支持查看生成的SQL语句。
常见问题
什么时候应该使用ORM,什么时候应该用原生SQL?
建议使用ORM处理日常的CRUD操作、业务逻辑相关的数据操作、需要数据库无关性的场景。建议使用原生SQL处理复杂的数据分析查询、大数据量批量操作、性能敏感的关键路径、复杂的多表JOIN查询。
什么是N+1查询问题?如何解决?
N+1查询是指先执行1次主查询获取N条记录,然后对每条记录再执行1次关联查询,总共N+1次查询。解决方法:1)使用joinedload预加载关联数据(JOIN方式);2)使用subqueryload(子查询方式);3)使用selectinload(IN查询方式)。
ORM会影响数据库性能吗?
会有一定影响。ORM需要将对象操作转换为SQL,这个转换过程有性能开销。此外,不当使用ORM(如N+1查询、全表加载)会导致严重的性能问题。但合理使用ORM(预加载、分页、只查询需要的列)可以将性能影响降到最低。
如何查看ORM生成的SQL语句?
在SQLAlchemy中,可以通过设置echo=True来打印生成的SQL:create_engine('sqlite:///db.db', echo=True)。也可以配置logging模块来捕获SQLAlchemy的SQL日志。
七、练习题
练习1:ORM概念理解
给定一个电商系统的数据库表结构(用户表、商品表、订单表、订单项表),使用原生SQL和ORM两种方式分别实现:1)查询某个用户的所有订单;2)查询某个订单包含的商品列表;3)统计每个用户的订单总金额。比较两种方式的代码差异和优缺点。
练习2:技术选型分析
假设你需要为一个新项目选择数据库访问方案。项目是一个包含用户管理、商品展示、订单处理、数据分析模块的电商平台。请分析:哪些模块适合使用ORM?哪些模块适合使用原生SQL?为什么?撰写一份技术选型报告。
小结
-
ORM概念:对象关系映射,将数据库表映射为Python类,行映射为实例,列映射为属性
-
ORM优势:提高开发效率、数据库无关性、类型安全、自动防SQL注入
-
ORM劣势:性能开销、学习成本、复杂查询困难、N+1查询问题
-
技术选型:根据项目规模和复杂度选择合适的ORM框架,必要时混合使用原生SQL
本文涉及AI创作
内容由AI创作,请仔细甄别