什么是ORM
对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在(原引自百度解释)。一句话解释就是:你不用写sql命令,用对象的方式操作数据库。
为什么要使用这个呢?1、随着面向对象的软件开发而产生,在业务实体的内存表现为对象,在数据库中表现为关系数据。 2、内存中的对象有关联和继承关系,关系数据库无法表达这种关系,因此ORM系统就是以这种中间件的形式存在,表现为对象到关系数据库的映射。
实际的企业级应用开发经常ORM,因此有必要学习一下。
SQLAlchemy的介绍
之前在Django中经常使用到ORM模块,SQLObject,Stom本文主要讲述SQLAlchemy的使用,在python web框架得到了广泛的应用。
安装和使用
安装SQLAlchemy建议直接pip安装,命令如下:
pip install SQLAlchemy
安装完成进行校验(安装完SQLAlchemy,还要安装对应的数据库接口模块)
C:\Users\pengfei>python
Python 3.7.5 (tags/v3.7.5:5c02a39a0b, Oct 15 2019, 00:11:34) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlalchemy
>>> sqlalchemy.__version__
'1.3.18'
>>> import pymysql
>>>> pymysql.__version__
'0.8.1'
数据库的连接与增删改查
对于数据库的安装我不再进行介绍,请读者自行安装,之后有时间我专门做对数据库的知识总结。
SQLAlchemy连接数据库使用的是数据库连接池技术,原理是在系统初始化的时候,将数据作为对象存在内存中,当用户访问数据库时,并非建立新的连接,而是从连接池中取出一个已建立连接的空闲连接对象。
SQLAlchemy初始化连接:
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:123456@localhost:3306/test?charset=utf8",echo=True,pool_size=5,max_overflow=4,
pool_recycle=7200,pool_timeout=30)
参数说明:
mysql+pymysql://root:123456@localhost:3306/test :
mysql指明数据库类型,pymysql表示连接数据库模块,root用户名,123456密码,localhost:3306,本地数据库和密码,test数据库的名称。
echo=True:相当于监视器,监视SQl执行情况
pool_size=5:设置的连接数,通常默认值够用
max_overflow:默认连接数是10,超过这个数,仍然可以访问,只是不放到pool连接池,被关闭
pool_recycle:连接重置时间
pool_timeou:连接超时时间,默认超时时间30s
更详细的信息见接口文档 :https://www.osgeo.cn/sqlalchemy/orm/tutorial.html
数据库的创建:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String,DateTime
engine = create_engine("mysql+pymysql://root:123456@localhost:3306/test?charset=utf8",echo=True,pool_size=5,max_overflow=4,
pool_recycle=7200,pool_timeout=30)
Base = declarative_base()
class mytable(Base):
__tablename__="mytable"
id = Column(Integer,primary_key=True)
name = Column(String(50),unique=True)
age = Column(Integer)
birth = Column(DateTime)
class_name = Column(String(50))
Base.metadata.create_all(engine)
执行命令后在数据库中创建出mytable数据库,引入declarative_base模块,生成Base对象,再创建一个mytable类,tablename="mytable"用于定义表名,id,name,age,birth,class_name定义各个字段Base.metadata.create_all(engine)在数据库中创建相应的数据表。
查询数据库的创建情况如下:
mysql> desc mytable;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | UNI | NULL | |
| age | int(11) | YES | | NULL | |
| birth | datetime | YES | | NULL | |
| class_name | varchar(50) | YES | | NULL | |
+------------+-------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
另外一种创建方式(如果数据库已存在会报错)
from sqlalchemy import Column, MetaData, ForeignKey, Table
from sqlalchemy.dialects.mysql import (INTEGER, CHAR)
meta = MetaData()
myclass = Table('myclass', meta,
Column('id', INTEGER, primary_key=True),
Column('name', CHAR(50), ForeignKey(mytable.name)),
Column('class_name', CHAR(50))
)
myclass.create(bind=engine)
数据库的删除,先删除mycalss,后删除mytable
myclass.drop(bind=engine)
Base.metadata.drop_all(engine)
添加数据
要对数据库进行操作,首先,先创建一个会话对象,该对象用于对数据的增删改查
from sqlalchemy.orm import sessionmaker
DBSession = sessionmaker(bind=engine)
session = DBSession()
new_data = mytable(name='pengfei',age=30,birth='1990-10-01',class_name='爱国班')
session.add(new_data)
session.commit()
session.close()
注:mytable是映射关系数据库的mytable表
数据库查看已添加的数据如下
mysql> select * from mytable;
+----+---------+------+---------------------+------------+
| id | name | age | birth | class_name |
+----+---------+------+---------------------+------------+
| 1 | pengfei | 30 | 1990-10-01 00:00:00 | 爱国班 |
+----+---------+------+---------------------+------------+
1 row in set (0.00 sec)
更新数据
ession.query(mytable).filter_by(id=1).update({ mytable.age : 18})
session.commit()
session.close()
如果批量更新就去除filter_by(id=1),相当于SQL语句的where
查询数据
get_data = session.query(mytable).all()
for i in get_data:
print('姓名:' + i.name)
print('班级:' + i.class_name)
session.close()
涉及的多表查询
# 内连接
get_data = session.query(mytable).join(myclass).filter(mytable.class_name == '有爱班').all()
print('数据类型是:' + str(type(get_data)))
for i in get_data:
print('名字:' + i.name)
print('班级:' + i.class_name)
# 外连接
get_data = session.query(mytable).outerjoin(myclass).filter(mytable.class_name == '爱国班').all()