1.1 配置和连接
- sqlalchemy python中最强大的ORM框架
- flask-sqlalchemy flask组件, 让flask可以接入sqlalchemy
- 安装 pip install flask-sqlalchemy
- 配置
- SQLALCHEMY_DATABASE_URI: 数据库连接地址
- SQLALCHEMY_TRACK_MODIFICATIONS: 是否追踪数据库修改, 开启后影响性能
- SQLALCHEMY_ECHO: 开启后, 可以在控制台打印底层执行的sql语
- 映射模型类
- 类 ---> 表
- 类属性 ---> 字段
- 对象 ---> 记录
- 使用
- 创建app对象
- 通过app对象创建数据库连接对象
- 建立映射模型
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 配置数据库的连接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
# 配置是否监听数据库变化, 性能较差, 不属于sqlalchemy本体
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 一旦开启, 可以显示底层执行的SQL语句
app.config['SQLALCHEMY_ECHO'] = True
# 创建数据库连接
db = SQLAlchemy(app)
# ORM 类->表 类属性->字段 对象->记录
class User(db.Model):
__tablename__ = 't_user' # 设置表明 默认为类名小写
id = db.Column(db.Integer, primary_key=True) # 主键 默认自增
name = db.Column(db.String(20), unique=True, index=True) # 设置唯一索引, 设置普通索引
email = db.Column(db.String(128), unique=True)
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
db.drop_all()
db.create_all()
app.run(debug=True, host='0.0.0.0')
1.2 增加数据
- 创建数据对象
- 添加到会话中(转成对应的sql语句)
- 提交会话(此时会提交事务, 事务提交失败, 会自动回滚)
@app.route('/')
def index():
"""增加数据"""
# 1. 创建数据对象
user1 = User(name='zs', age=20)
# user1.name = 'zs'
# user1.age = 20
# 2. 添加到会话中 (转为对应的sql语句)
db.session.add(user1)
# 添加多个数据
# db.session.add_all([user1, user2, user3])
# sqlalchemy会自动创建隐式的事务, 并将sql操作添加到事务中
# 3. 提交会话, 此时就会提交事务, 事务提交失败, 会自动回滚
db.session.commit()
return 'index'
1.3 数据查询
- 查询所有用户数据
User.query.all() # 返回的是列表, 里边包含的是模型对象
- 查询有多少个用户
User.query.count()
- 查询第一个用户
User.query.first() # 返回模型对象
- 查询id为4的用户[3种方式]
User.query.get(4) # 根据id查询
User.qeury.filter_by(id=4).all() # 简单查询器, 通过关键字实参来匹配字段,
# 返回BaseQuery对象, 可以续接更复杂的查询条件 all/count/first User.query.filter(User.id==4).first() # 复杂查询器 参数为恒等式/函数 返回BaseQuery对象
- 查询名字结尾字符为g的所有用户[开始 / 包含]
User.query.filter(User.name.endswith('g')).all() # 名字以g结尾
User.query.filter(User.name.startwith('w')).all() # 名字以w开头
User.query.filter(User.name.contains('n')).all() # 名字包含n
User.query.filter(User.name.like('w%n%g')).all() # 模糊查询
- 查询名字和邮箱都以 li 开头的所有用户[2种方式]
User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all()
from sqlalchemy import and_
User.query.filter(and_(User.name.startswith('li'), User.emailstartswith('li'))).all()
- 查询age是25 或者 'email' 以 'itheima.com' 结尾的所有用户
from sqlalchemy import or_
User.query.filter(or_(User.age==25, User.email.endswith('itheima.com'))).all()
- 查询名字不等于 wang 的所有用户[2种方式]
from sqlalchemy import not_
User.query.filter(not_(User.name=='wang'))).all() User.query.filter(User.name != 'wang')).all()
- 查询id为 [1, 3, 5, 7, 9]的用户
User.query.filter(User.id.in_([1,3,5,7,9])).all()
- 所有用户先按年龄从小到大, 再按id从大到小排序, 取前5个
User.query.order_by(User.age, User.id.desc())).limit(5).all()
- 查询年龄从小到大第2-5位的数据
User.query.order_by(User.age).offset(1).limit(4).all()
- 分页查询, 每页3个, 查询第2页的数据
pn = User.qeury.paginate(2, 3)
pn.items # 该页的数据
pn.pages # 总页数
pn.page # 当前页码
- 查询每个年龄的人数
from sqlalchemy import func
db.session.query(User.age, func.count(User.name)).group_by(User.age).all()
- 只查询所有人的性命和邮箱, 优化查询(两种方式) 默认使用 select *
users = User.query.options(load_only(User.name, User.email)).all() data = db.session.query(User.name, User.email).all()
1.3.1 慢查询分析
# 在mysql的配置文件 /etc/mysql/mysql.conf.d/mysql.cnf[mysqld]中配置懒查询
slow_query_log = ON # 是否已经开启慢查询
long_query_time = 1 # 慢查询统计标准, 超过1秒
slow_query_log_file = /usr/local/mysql/data/zzz-slow.log # 慢查询日志文件路径 log_queries_not_using_indexes = 1 # 如果值设置为ON, 则会记录所有利用索引的查询,性能优化时开启此项, 平时不要开启
# 重启mysql sudo /etc/init.d/mysql restart
# 查看懒查询启动情况 show variables like '%slow%'; show varibales like '%long_query_time%';
# 懒查询分析工具
mysqldumpslow
# -s: 排序方式 c 查询次数 t 查询时间 l 等待锁的时间 r 返回的记录数 at 平均查询时间
# -t: 返回前面多少条的数据;
# -g: 包含什么, 大小写不敏感的;
# 返回记录中查询次数最多的10个语句
sudo mysqldumpslow -s c -t 10 /usr/local/mysql/data/zzz-slow.log
# 返回记录中含有'user', 并且按照平均时间排序最慢的前10条语句
sudo mysqldumpslow -s at -t 10 -g 'user' /usr/local/mysql/data/zzz-slow.log
1.4 更新和删除
- 修改name='zs'的用户名为'lisi'
# 先查询, 后修改
user_obj = User.query.filter_by(name='zs').first()
user_obj.name = 'lisi'
# 使用update的子查询, update t_user set name='lisi' where name='zs';
User.query.filter_by(name='zs').update({'name':'lisi'})
db.session.commit() # 提交会话
- 删除name='zs'的用户
user_obj = User.query.filter_by(name='zs').first()
db.session.delete(user_obj) # delete的子查询
User.query.filter_by(name='zs').delete()
db.session.commit()
1.5 管道
# sqlalchemy对mysql进行了优化, 实现了类似redis管道的机制, 如果会话中没有要执行查询
# (包含更新/删除的子查)和主动flush, 则所有的sql操作会在commit时才一起发送给mysql服务器
# 添加数据
user1 = User(name='zs', age=20)
db.session.add(user1)
# User.query.all() # 会将当前会话中的所有sql立即发送给mysql服务器
# db.session.flush() # 会将当前会话中的所有sql立即发送给mysql服务器
db.session.commit()