✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,前后端开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,linux,shell脚本等实操经验,网站搭建,面试宝典等分享。所属的专栏:flask框架零基础,进阶应用实战教学
景天的主页:景天科技苑
文章目录
- flask项目中数据库连接设置
- 数据库基本操作
- 模型类定义
- flask中数据表操作
- 创建和删除表
- 数据操作
- 添加一条数据
- 添加多条数据
- 更新操作
- 删除操作
- 关于数据库锁
- 总结
上一章,我们学到了在python中怎么使用SQLAlchemy来操作数据库,在工作中,我们经常结合flask来操作数据库。本章我们来一起深入探讨下!!!
flask项目中数据库连接设置
- 在 Flask-SQLAlchemy 中,数据库的链接配置信息使用URL指定,而且程序使用的数据库必须保存到Flask的 SQLALCHEMY_DATABASE_URI 配置项中
manage.py,代码:
# SQLAlchemy的链接配置:"数据库名://账户名:密码@服务器地址:端口/数据库名称?配置参数选项"
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:123@127.0.0.1:3306/flaskdemo?charset=utf8mb4"
# 如果不使用mysqldb改用pymysql,则需要在连接时指定pymysql
# app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:Jin*******7!@10.10.0.52:3306/students?charset=utf8mb4"
其他设置项:
# 动态追踪修改设置,如未设置只会提示警告
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
# 查询时会显示原始SQL语句
app.config["SQLALCHEMY_ECHO"] = True
常用的SQLAlchemy字段类型与python数据类型对照
常用的SQLAlchemy列约束选项
数据库基本操作
- 在SQLAlchemy中,添加、修改、删除操作,均由数据库会话(sessionSM)管理。
- 会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 db.session.commit() 方法提交会话。
- 在SQLAlchemy 中,查询操作是通过 query 对象操作数据。
- 最基本的查询是返回表中所有数据,也可以通过filter或filter_by过滤器进行更精确的数据库查询。
模型类定义
我们后面会把模型创建到单独的文件中,但是现在我们先把模型类写在main.py文件中。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 连接数据库连接url
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:Jinghao31357!@10.10.0.52:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
# 查询时会显示原始SQL语句
app.config["SQLALCHEMY_ECHO"] = True
# 把SQLAlchemy组件注册到项目中
db = SQLAlchemy()
db.init_app(app)
#创建模型类
class Student(db.Model):
"""学生信息模型"""
#下面的字段配置相当于执行sql语句如下
"""
CREATE TABLE tb_student2 (
id INTEGER NOT NULL COMMENT '主键' AUTO_INCREMENT,
name VARCHAR(15) COMMENT '姓名',
age SMALLINT COMMENT '年龄',
sex BOOL COMMENT '性别',
email VARCHAR(128) COMMENT '邮箱地址',
money NUMERIC(10, 2) COMMENT '钱包',
PRIMARY KEY (id),
UNIQUE (email)
)
"""
# 声明与当前模型绑定的数据表名称
__tablename__ = "tb_student2"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(15), index=True, comment="姓名")
age = db.Column(db.SmallInteger, comment="年龄")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(128), unique=True, comment="邮箱地址")
money = db.Column(db.Numeric(10, 2), default=0.0, comment="钱包")
def __repr__(self): # 相当于django的__str__
return f"{self.name}<{self.__class__.__name__}>"
class Course(db.Model):
"""课程模型"""
"""
CREATE TABLE tb_course (
id INTEGER NOT NULL COMMENT '主键' AUTO_INCREMENT,
name VARCHAR(255) COMMENT '课程',
price NUMERIC(8, 2) COMMENT '价格',
PRIMARY KEY (id),
UNIQUE (name)
)
"""
__tablename__ = "tb_course"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(255), unique=True, comment="课程")
price = db.Column(db.Numeric(8, 2), comment="价格")
def __repr__(self): # 相当于django的__str__
return f"{self.name}<{self.__class__.__name__}>"
class Teacher(db.Model):
"""老师模型"""
"""
CREATE TABLE tb_teacher (
id INTEGER NOT NULL COMMENT '主键' AUTO_INCREMENT,
name VARCHAR(255) COMMENT '姓名',
`option` ENUM('讲师','助教','班主任'),
PRIMARY KEY (id),
UNIQUE (name)
)
"""
__tablename__ = "tb_teacher"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(255), unique=True, comment="姓名")
option = db.Column(db.Enum("讲师", "助教", "班主任"), default="讲师")
def __repr__(self):
return f"{self.name}<{self.__class__.__name__}>"
if __name__ == '__main__':
#要想执行创建表,需要调用db.creat_all(),db要想被调用,需要放到app上下文里面
with app.app_context():
# 如果没有提前声明模型中的数据表,则可以采用以下代码生成数据表,
# 如果数据库中已经声明了有数据表,则不会继续生成
db.create_all()
app.run(debug=True)
flask中数据表操作
创建和删除表
创建表
# 在视图内调用:
@app.route("/create")
def create_table():
db.create_all() # 为项目中被识别的所有模型创建数据表
return "ok"
# 在视图以外的地方调用:
with app.app_context():
# create_all()方法执行的时候,需要放在模型的后面
# 检测数据库中是否存在和模型匹配的数据表。
# 如果没有,则根据模型转换的建表语句进行建表。
# 如果找到,则不会进行额外处理
db.create_all()
删除表
# 在视图内调用:
@app.route("/drop")
def drop_table():
db.drop_all() # 为项目中被识别的所有模型删除数据表
return "ok"
# 在视图以外的地方调用:
with app.app_context():
db.drop_all() # 慎用,很给力的!!这表示删除数据库中所有模型对应的表。
数据操作
添加一条数据
#在视图函数中实现增删改查
@app.route("/data")
def data():
"""添加数据"""
# # 添加一条数据
student = Student(
name="小明",
age=17,
sex=True,
email="xiaoming@qq.com",
money=30.50
)
db.session.add(student)
db.session.commit()
return "ok"
get请求访问data路径
可以看到数据已被添加到表中
添加多条数据
student_list = [
Student(name="小黑", age=16, sex=True, email="xiaohei@qq.com", money=1000),
Student(name="小红", age=15, sex=False, email="xiaohong@qq.com", money=1200),
Student(name="小兰", age=11, sex=True, email="xiaolan@qq.com", money=600),
Student(name="小白", age=21, sex=False, email="xiaobai@qq.com", money=2900),
]
db.session.add_all(student_list)
db.session.commit()
查看数据库
更新操作
更新一条数据
student = Student.query.get(3)
student.age = 18
db.session.commit()
更新之前,我们先看下3号的年龄
浏览器访问后查看
可见年龄被修改成18
更新多条数据
Student.query.filter(Student.sex == True).update({
Student.money: Student.age * 100,
})
db.session.commit()
可见sex为True的money改成了年龄乘以100
删除操作
删除一条数据
student = Student.query.get(5)
db.session.delete(student)
db.session.commit()
id为5的数据被删除
删除多条数据
Student.query.filter(Student.sex==False).delete()
db.session.commit()
删之前先看看数据库表数据
浏览器访问/data
查看数据库,sex为False的全部被删除
完整代码:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 连接数据库连接url
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:Jinghao31357!@10.10.0.52:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
# 查询时会显示原始SQL语句
app.config["SQLALCHEMY_ECHO"] = True
# 把SQLAlchemy组件注册到项目中
db = SQLAlchemy()
db.init_app(app)
#创建模型类
class Student(db.Model):
"""学生信息模型"""
# 声明与当前模型绑定的数据表名称
__tablename__ = "tb_student2"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(15), index=True, comment="姓名")
age = db.Column(db.SmallInteger, comment="年龄")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(128), unique=True, comment="邮箱地址")
money = db.Column(db.Numeric(10, 2), default=0.0, comment="钱包")
def __repr__(self): # 相当于django的__str__
return f"{self.name}<{self.__class__.__name__}>"
class Course(db.Model):
"""课程模型"""
__tablename__ = "tb_course"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(255), unique=True, comment="课程")
price = db.Column(db.Numeric(8, 2), comment="价格")
def __repr__(self): # 相当于django的__str__
return f"{self.name}<{self.__class__.__name__}>"
class Teacher(db.Model):
"""老师模型"""
__tablename__ = "tb_teacher"
id = db.Column(db.Integer, primary_key=True, comment="主键")
name = db.Column(db.String(255), unique=True, comment="姓名")
#枚举类型
option = db.Column(db.Enum("讲师", "助教", "班主任"), default="讲师")
def __repr__(self):
return f"{self.name}<{self.__class__.__name__}>"
#在视图函数中实现增删改查
@app.route("/data")
def data():
"""添加数据"""
# # 添加一条数据
# student = Student(
# name="小明",
# age=17,
# sex=True,
# email="xiaoming@qq.com",
# money=30.50
# )
# db.session.add(student)
# db.session.commit()
# # 添加多条数据
# student_list = [
# Student(name="小黑", age=16, sex=True, email="xiaohei2@qq.com", money=1000),
# Student(name="小红", age=15, sex=False, email="xiaohong2@qq.com", money=1200),
# Student(name="小兰", age=11, sex=True, email="xiaolan2@qq.com", money=600),
# Student(name="小白", age=21, sex=False, email="xiaobai2@qq.com", money=2900),
# ]
# db.session.add_all(student_list)
# db.session.commit()
"""更新操作"""
# # 更新一条数据
# student = Student.query.get(3)
# student.age = 18
# db.session.commit()
# 更新多条数据
# Student.query.filter(Student.sex == True).update({
# Student.money: Student.age * 100,
# })
# db.session.commit()
"""删除操作"""
# # 删除一条数据
# student = Student.query.get(5)
# db.session.delete(student)
# db.session.commit()
# # 删除多条数据
Student.query.filter(Student.sex==False).delete()
db.session.commit()
return "ok"
if __name__ == '__main__':
#要想执行创建表,需要调用db.creat_all(),db要想被调用,需要放到app上下文里面
with app.app_context():
# 如果没有提前声明模型中的数据表,则可以采用以下代码生成数据表,
# 如果数据库中已经声明了有数据表,则不会继续生成
db.create_all()
app.run(debug=True)
关于数据库锁
悲观锁,是属于数据库中的一种互斥锁机制,但是乐观锁并非真正的数据库锁。
2种锁都是数据库在应对并发操作时,防止出现资源抢夺的,基于不同人生观所实现2种解决方案。
悲观锁的基本使用:
>>> 数据库终端开始
begin; -- 开启事务
select * from db_student where student_id = 5 for update; -- 添加一把更新锁【悲观锁】
.... -- 在事务提交之前,任何第三方连接都不能修改 student_id = 5这条数据
update from db_student set age = 16 where student_id = 5;
commit; -- 提交事务
<<< 数据库终端开始
悲观锁的问题:
- 提前锁定数据,形成串行化,形成阻塞,不利于性能发挥,不适用高并发场景。
- 悲观锁只能保证数据的一致性,不能保证脏数据的出现
乐观锁的出现就是为了解决悲观锁的问题。
举例:双11活动,商城里面id=5的商品的库存num=10了,现在我们要基于乐观锁和悲观锁来解决下单过程中,出现的资源抢夺现象,避免出现超卖(商品数量不能为负数)。
乐观锁:
—> begin; 开启事务
—> 先查看库存,记录当前库存 original_num=10
—> 进行下单操作,买6件
—> 付款
—> 扣除库存 update goods set num=num-6 where num=original_num and id=5; # 增加更新条件,判断库存是否还是原来
如果执行成功,则表示没有人抢,购买成功
—> commit;
如果执行失败,则表示已经有人先抢购
—> rollback;
悲观锁:
—> begin; 开启事务
—> 先给id=5的数据,加锁
select * from goods where id=5 for update;
—> 进行下单操作,买6件
—> 付款
—> 扣除库存 update from goods set num=num-6 where id=5;
—> 执行成功解锁
—> commit; 提交事务
总结
本文详述了在flask项目中结合SQLAlchemy操作mysql数据库的详细用法,非常实用,感兴趣的朋友可以一键三连,flask的高阶用法持续更新中!!!