回顾:
-
1 pipreqs–>快速生成项目的依赖
-
2 函数和方法
-
3 threading包下的local类—》实例化得到对象—》多线程并发操作————>数据不会错乱
-加锁
-每条线程操作自己的数据
其实字典和列表都不是并发安全的,多个线程同时往字典里面写数据,会乱;写数据的过程是先取到、再写、再给它,这3步叫临界区
所以这3步,必须要做成原子性的,要加锁 -
4 自己写–》兼容协程(协程是单线程内的并发)
-
5 flask请求上下文:RequestContext–ctx:request,session,flash
-
6 flask应用上下文:AppContext—> app_ctx:当前app,g
-
7 flask请求上下文源码分析
1 请求来了执行---》app()--->触发类的__call__--->self.wsgi_app(environ, start_response)---> 2 ctx = self.request_context(environ)-->封装了request和session 3 ctx.push()--->_request_ctx_stack.push(self)-->self是ctx 4 _request_ctx_stack是LocalStack类的对象--》push 5 LocalStack的push方法源码
def push(self, obj):
rv = getattr(self._local, "stack", None)
if rv is None:
self._local.stack = rv = []
# self._local={'线程id1':{'stack':[ctx,]},'线程id2':{'stack':[ctx,]},'线程id3':{'stack':[ctx,]}}
rv.append(obj)
return rv
6 LocalStack对像中的 _local--->init初始化出来的
-self._local = Local() # 咱们自己写的可以多线程并发访问的Local
7 _local={线程或协程id号:{stack:[ctx]},线程或协程id号:{stack:[ctx]}}
_local.stack--》取stack的值,在不同协程下,取到的是自己的
-
8 在视图函数中使用request,session—》都是当此请求的request和session,但是我们使用了全局变量。打印的真的是当次请求的Request类的对象,但实际上request根本不是Request类的对象,LocalProxy类的对象,LocalProxy类重写了__str__
-
9 print(request)的时候–》类的__str__
-
10 LocalProxy把所有的魔法方法都重写了,因为它是个代理类
-
11 request = LocalProxy(partial(_lookup_req_object, “request”))
-init---》def __init__(self, local, name=None):--->object.__setattr__(self, "_LocalProxy__local", local)--->local就是偏函数
-
12 LocalProxy—》str—>_get_current_object()是LocalProxy类的方法
-
13 LocalProxy._get_current_object()—》return
self.__local()–》加括号执行偏函数—》
partial(_lookup_req_object, “request”)()—>_lookup_req_object(‘request’)– -
14 返回了当前线程所在的ctx中的request对象
-
15 request.method–>就是当前线程的request对象的method方法
-
16 在视图函数中打印print(session)—>是当此请求的session
sqlalchemy快速使用
ORM框架:对象关系映射,把数据库中数据转成对象的过程
SQLAlchemy是一个基于Python实现的ORM框架,跟web框架无关,独立的
django的orm,sqlalchemy(大而重),peewee(小而轻)
(了解)国人开源的一个异步orm框架:GINO
Python界没有一个特别好的微服务框架:nameko
java微服务框架:dubbo(阿里开源),springcloud(一天下)
go微服务框架:grpc,go-zero,go-micro
pip install sqlalchemy
django中的原生sql
ret = Author.objects.raw('select * from app01_author where nid>1')
ret = Author.objects.raw('select * from app01_book where nid>1')
强大的地方,Author表去查book都可以,一样的字段可以映射上,不一样的就没有
很多人了解了这个写法之后,就不想写orm了,因为复杂的,orm写不出来
django中如何反向生成models
公司里面已经有表了,现在根据表反向生成models
python manage.py inspectdb > app/models.py #会自动把表
正常操作:模型表中新增字段---》两条命令---》同步到数据中
特殊操作:模型表中新增字段---》不要了---》在数据中增加字段;此时只要对上就行了。但是后面不能执行那两条命令了,就会报错
就是一旦不用,以后都不用
执行原生sql
代码
import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine
engine = create_engine(
"mysql+pymysql://root:111@127.0.0.1:3306/cnblogs", # root用户,密码是111,cnblogs是库名
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置),就是说5个链接,用多久之后会被回收,然后再生成再用
) # pool_recycle=-1就是不重置
def task(arg):
conn = engine.raw_connection() # 创建原生的连接池
cursor = conn.cursor()
cursor.execute(
"select * from article"
)
result = cursor.fetchall()
print(result)
cursor.close()
conn.close()
for i in range(20):
t = threading.Thread(target=task, args=(i,))
t.start()
创建和删除表
建表模型,一般建在models.py里面
在sqlalchemy中必须要以__tablename__ = 'users' 指定表名(不像django中meta)
所有的列都是Column
__table_args__:table的一些参数
双下划线开头的,在django里面都是写在Meta里面的
UniqueConstraint:联合唯一(django里面的Uniquetogether)
表模型需要继承
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
上面的表已经弄好了,需要把通过
把表同步到数据库中(连哪个库,哪个地址)
使用engin指定地址和库
def init_db():
engine = create_engine(
"mysql+pymysql://root:111@127.0.0.1:3306/aaa?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Base.metadata.create_all(engine) # 被Base管理的所有表,创建出来
但是sqlalchemy原生:只能创建和删除表不能新增和删除修改字段,不能创建数据库
(django里面只要把字段改成别的名字,迁移一下就行)
但是flask sqlalchemy 加flask-migrate可以实现。有第三方库
下面再看删除表
def drop_db():
engine = create_engine(
"mysql+pymysql://root:111@127.0.0.1:3306/aaa?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Base.metadata.drop_all(engine) # 删除所有被Base管理的表
sqlalchemy原生:只能创建和删除表不能新增、删除修改字段,不能创建数据库(django也不能创建数据库,都是手动创建出来的)
一对多、多对多
一对多关系:一个Hobby可以有多个人喜欢,关联字段写在多的一方,Person
多对多关系
多对多关系:男孩和女孩约会,一个男孩可以约多个女孩,一个女孩可以约多个男孩
多对多要中间表
models.py代码
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
from sqlalchemy import create_engine
import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Users(Base):
id = Column(Integer, primary_key=True) # id 主键
name = Column(String(32), index=True, nullable=False) # name列,索引,不可为空
email = Column(String(32), unique=True) # 唯一
# datetime.datetime.now不能加括号,加了括号,以后永远是当前时间
ctime = Column(DateTime, default=datetime.datetime.now)
extra = Column(Text, nullable=True)
__tablename__ = 'users' # 数据库表名称
__table_args__ = (
UniqueConstraint('id', 'name', name='uix_id_name'), # 联合唯一
Index('ix_id_name', 'name', 'email'), # 联合索引
)
def __str__(self):
return self.name
def __repr__(self):
return self.name
# 一对多关系:一个Hobby可以有多个人喜欢,关联字段写在多的一方,Person
class Hobby(Base):
__tablename__ = 'hobby'
id = Column(Integer, primary_key=True)
caption = Column(String(50), default='篮球')
class Person(Base):
__tablename__ = 'person'
nid = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=True)
# hobby指的是tablename而不是类名,跟hobby表的id字段建立外键关系
hobby_id = Column(Integer, ForeignKey("hobby.id"))
# 跟数据库无关,不会新增字段,只用于快速链表操作
# 类名,backref用于反向查询
hobby = relationship('Hobby', backref='persons')
# 多对多关系:男孩和女孩约会,一个男孩可以约多个女孩,一个女孩可以约多个男孩
class Boy2Girl(Base):
__tablename__ = 'boy2girl'
id = Column(Integer, primary_key=True, autoincrement=True) # autoincrement自增
girl_id = Column(Integer, ForeignKey('girl.id'))
boy_id = Column(Integer, ForeignKey('boy.id'))
class Girl(Base):
__tablename__ = 'girl'
id = Column(Integer, primary_key=True)
name = Column(String(64), unique=True, nullable=False)
class Boy(Base):
__tablename__ = 'boy'
id = Column(Integer, primary_key=True, autoincrement=True) # autoincrement自增
name = Column(String(64), unique=True, nullable=False)
# 与生成表结构无关,仅用于查询方便,放在哪个单表中都可以
girls = relationship('Girl', secondary='boy2girl', backref='boys')
# 把表同步到数据库中(连哪个库,哪个地址)
# 使用engin指定地址和库
# 只能创建和删除表不能新增和删除修改字段,不能创建数据库
def init_db():
engine = create_engine(
"mysql+pymysql://root:111@127.0.0.1:3306/aaa?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Base.metadata.create_all(engine) # 被Base管理的所有表,创建出来
def drop_db():
engine = create_engine(
"mysql+pymysql://root:111@127.0.0.1:3306/aaa?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Base.metadata.drop_all(engine) # 删除所有被Base管理的表
if __name__ == '__main__':
init_db()
# drop_db()
sqlalchemy的基本增删查改
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Users, Person, Hobby, Girl, Boy, Boy2Girl
# 单表的基本增删查改
# 第一步:得到engine对象
engine = create_engine("mysql+pymysql://root:111@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)
# 第二步:得到Session对象,当成一个类
Session = sessionmaker(bind=engine)
# 第三步:创建session对象
# 每次执行数据库操作时,都需要创建一个session
session = Session()
# 第四步:以后使用session来操作数据
##################### 增单个 #####################
# 先创建出一个user对象
lqz = Users(name='lqz', email='33@qq.com')
# 把对象增加到数据库中
session.add(lqz) # 只能同时增一个
# 提交事务
session.commit()
# 把连接放回到池中
session.close()
##################### 增多个 #####################
lqz = Users(name='lqz1', email='333@qq.com')
egon = Users(name='egon', email='343@qq.com')
lyf = Girl(name='刘亦菲') # 在Girl表中
# 把对象增加到数据库中
session.add_all([lqz, egon, lyf])
# 提交事务
session.commit()
# 把连接放回到池中
session.close()
##################### 基本的查(查是最多的,现在先讲简单的) #####################
lqz=session.query(Users).filter_by(name='lqz').first() # 查一个,返回Users对象
这边不显示名字
重写__str__就可以了
重写__repr__就可以了
##################### 删除(查完再删) #####################
查一个返回对象,查多个,返回列表
##################### 修改 #####################
res=session.query(Users).filter_by(name='lqz1').update({'name':'lqz_nb'}) #必须放在一个字典里面改
session.commit()
session.close()
# 类似于原来的F查询,把表中字段取出来使用
# synchronize_session=False 表示字符串相加
res=session.query(Users).filter_by(name='lqz_nb').update({Users.name: Users.name + "099"}, synchronize_session=False)
session.commit()
session.close()
# synchronize_session="evaluate" 表示数字相加(如果转不成数据,其实有错,直接设为0)
session.query(Users).filter_by(name='1').update({"id": Users.id + 10}, synchronize_session="evaluate")
session.commit()
session.close()
查询操作
查询所有
select * from users;
r1 = session.query(Users).all() #结果是一个列表
给字段重命名
select name as xx ,email from users;
r2 = session.query(Users.name.label('xx'), Users.email).all()
filter和filter_by的区别
filter传的是表达式
r = session.query(Users).filter(Users.id >= 10).all()
r = session.query(Users).filter(Users.id == 3).all()
filter_by传的是参数
r = session.query(Users).filter_by(name='egon').all() #列表
r = session.query(Users).filter_by(name='egon').first() #一个数据对象
:value 和:name 相当于占位符,用params传参数
from sqlalchemy.sql import text
select * from users where id <224 and name = egon1
r = session.query(Users).filter(text("id<:value and name=:name")).params(value=10, name='egon1').all()
自定义查询sql(了解)
r = session.query(Users).from_statement(text("SELECT * FROM users where name=:name")).params(name='egon').all()
这个里面可以写更复杂的
条件
ret = session.query(Users).filter_by(name='egon').all()
表达式,and条件连接
ret = session.query(Users).filter(Users.id > 1, Users.name == 'egon').all() #id大于1,并且name是egon
select * from user where name=egon id between 1 and 3;
ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'egon') #id是1-3之间,并且name是egon
注意下划线
ret = session.query(Users).filter(Users.id.in_([1,3,4])) #id是1,3,4的任一个的
~非:除。。外
ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all() #id是除了1,3,4之外的
二次筛选
ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='egon'))).all()
or_包裹的都是or条件
and_包裹的都是and条件 Q查询
from sqlalchemy import and_, or_
ret = session.query(Users).filter(and_(Users.id > 2, Users.name == 'egon')).all()
ret = session.query(Users).filter(or_(Users.id >10, Users.name == 'egon')).all()
ret = session.query(Users).filter(
or_(
Users.id < 2,
and_(Users.name == 'egon', Users.id > 3),
Users.extra != ""
)).all() #or里面的3个是或的条件,3个里面其中一个又是and条件
通配符,以e开头,不以e开头
ret = session.query(Users).filter(Users.name.like('e%')).all() #查出已e开头的所有的名字
ret = session.query(Users).filter(~Users.name.like('e%')).all()
限制,用于分页,区间
每页显示10条,拿第8页
ret = session.query(Users)[(8-1)*10:10]
排序,根据name降序排列(从大到小)
ret = session.query(Users).order_by(Users.name.desc()).all() #.desc()可以不写
第一个条件重复后,再按第二个条件升序排
ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc())
分组 (就是把一样的归成一类):一旦用了分组,查询的字段只能是分组字段和聚合函数的字段
from sqlalchemy.sql import func
# 原生sql:select * from users group by user.extra
例子:
1 egon 32@qq.com
2 egon 31@qq.com
3 lqz 34@qq.com
一旦用了分组,按名字分组,就成了两类;一类是egon。一类是lqz
但是名字是egon的,有两个id。两个邮箱,不知道拿谁,所以要取的字段必须是分组字段和聚合函数的字段
所以不能select id,不能select 邮箱,只能是select name(name就是分组字段,group by后面的)
select * from users group by user.name
ret = session.query(Users).group_by(Users.extra)
聚合函数min max avg sum count
分组之后取最大id,id之和,最小id
select max(id),sum(id),min(id) from users group by users.name
ret = session.query(
func.max(Users.id),
func.sum(Users.id),
func.min(Users.id)).group_by(Users.name)
haviing筛选
分组筛选完了,再去过滤
原生sql:select max(id),sum(id),min(id) as min_id from users group by users.name having min_id>2
django的orm:Users.object.all().value(Users.name).annotate(min_id=func.min(Users.id),max_id=func.max(Users.id),sum_id=sum(Users.id)).filter(min_id__gte=2).values(min_id,max_id,sum_id)
django的orm补充:
filter在annotate前表示过滤
value在annotate前表示分组的字段
filter在annotate后表示having
value在annotate后表示取字段
ret = session.query(
func.max(Users.id),
func.sum(Users.id),
func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all()
连表(默认用forinkey关联)
select * from person,hobby where person.hobby_id=hobby.id
ret = session.query(Person, Hobby).filter(Person.hobby_id == Hobby.id)
join表,默认是inner join(内连接)
面试题:左连接、右链接。内连接的区别?
左连接以左表数据为准、右链接以右边数据为准、内连接以共有的数据为准
select * from person inner join on person.hobby_id=hobby.id
ret = session.query(Person).join(Hobby)
isouter=True 外连,表示Person left join Favor,没有右连接,反过来即可
ret = session.query(Person).join(Hobby, isouter=True)
ret = session.query(Hobby).join(Person, isouter=True)
打印原生sql(去掉后面的.all())
aa=session.query(Person).join(Favor, isouter=True)
print(aa)
自己指定on条件(连表条件),第二个参数,支持on多个条件,用and_,同上
SELECT * FROM person LEFT OUTER JOIN hobby ON hobby.id = person.id
ret = session.query(Person).join(Hobby,Person.nid==Hobby.id, isouter=True)
组合(了解)UNION 操作符用于合并两个或多个 SELECT 语句的结果集
union和union_all的区别?
答:union去重、union_all不去重
q1 = session.query(Person.name).filter(Person.nid > 0)
结果:
lqz
lyf
pyy
q2 = session.query(Hobby.caption).filter(Hobby.id > 0)
结果:
lqz
egon
lyf
ret = q1.union(q2).all()
结果:
lqz
lyf
pyy
egon
ret = q1.union_all(q2).all()
结果:
lqz
lyf
pyy
lqz
egon
lyf
sqlalchemy的关联操作
基于对象的跨表查: book.publish
基于连表的跨表查: __连表
一对多和多对多关系的新增和查询
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Users, Person, Hobby, Girl, Boy, Boy2Girl
from sqlalchemy.sql import text
# 第一步:得到engine对象
engine = create_engine("mysql+pymysql://root:111@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)
# 第二步:得到Session对象,当成一个类
Session = sessionmaker(bind=engine)
# 第三步:创建session对象
# 每次执行数据库操作时,都需要创建一个session
session = Session()
一对多关系
####################### 新增 #########################
p = Person(name='刘清政', hobby_id=1)
hobby = Hobby(caption='橄榄球')
session.add_all([p, hobby])
session.commit()
####################### 新增方式二 #########################
p = Person(name='egon', hobby=Hobby(caption='保龄球'))
session.add_all([p, ])
session.commit()
####################### 基于对象的跨表查询 --->正向查询 #########################
lqz=session.query(Person).filter_by(name='刘清政').first()
print(lqz.hobby_id)
print(lqz.hobby.caption)
####################### 基于对象的跨表查询的反向查询 #########################
lq = session.query(Hobby).filter_by(caption='篮球').first() #拿到篮球的对象
print(lq.persons) #查到所有喜欢篮球的人
多对多关系
一对多的时候,关联关系写在多的一方。多对多的时候,根本就没有这个字段,是一个中间表。写在哪一方都可以
####################### 快速新增,前提是Boy表中有girls字段 #########################
boy = Boy(name='小王', girls=[Girl(name='小花'), Girl(name='小华')])
session.add(boy)
session.commit()
# 如果没有这个字段,就需要这样新增
####################### 笨办法 #########################
boy = Boy(name='小刚')
girl1 = Girl(name='小静')
girl2 = Girl(name='小月')
session.add_all([boy,girl1,girl2])
session.commit()
b1=Boy2Girl(girl_id=4,boy_id=2)
b2=Boy2Girl(girl_id=5,boy_id=2)
session.add_all([b1,b2])
session.commit()
####################### 基于对象的跨表查 正向 #########################
xg=session.query(Boy).filter_by(name='小刚').first()
print(xg.girls)
####################### 反向 #########################
xj=session.query(Girl).filter_by(name='小静').first()
print(xj.boys)
基于scoped_session实现线程安全
当我们把项目继承到flask里面之后,
# 每次执行数据库操作时,都需要创建一个session
session = Session()
这个session就是一个全局的变量,就会出现多个线程公用这一个连接,scoped_session解决了这个问题
来一个新的线程都会创建一个scoped_session(有threading.local())
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from models import Users
engine = create_engine("mysql+pymysql://root:111@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
# 线程安全,基于本地线程实现每个线程用同一个session
# 特殊的:scoped_session中有原来方法的Session中的一下方法:
# public_methods = (
# '__contains__', '__iter__', 'add', 'add_all', 'begin', 'begin_nested',
# 'close', 'commit', 'connection', 'delete', 'execute', 'expire',
# 'expire_all', 'expunge', 'expunge_all', 'flush', 'get_bind',
# 'is_modified', 'bulk_save_objects', 'bulk_insert_mappings',
# 'bulk_update_mappings',
# 'merge', 'query', 'refresh', 'rollback',
# 'scalar'
# )
# scoped_session类并没有继承Session,但是却又它的所有方法。是动态的一个一个的写进去的
# session=Session()
session = scoped_session(Session)
# ############# 执行ORM操作 #############
obj1 = Users(name="egon111")
session.add(obj1)
# 提交事务
session.commit()
# 关闭session
session.close()
sqlalchemy集成到flask中
from flask import Flask, jsonify
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from models import Users
engine = create_engine("mysql+pymysql://root:111@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
app = Flask(__name__)
@app.route('/<string:name>')
def index(name):
egon = session.query(Users).filter_by(name=name).first()
egon_dic = {'name': egon.name, 'email': egon.email}
return jsonify(egon_dic)
if __name__ == '__main__':
app.run()
上面是自己实现的,第三方帮我们做了,使用flask_sqlalchemy集成到flask中
我们上面学的是sqlalchemy的使用,它可以用和任何框架结合起来,甚至django,只是没有人这样用
flask_sqlalchemy的快速使用
用的就是db.session、和db.model
使用步骤
1 导入from flask_sqlalchemy import SQLAlchemy 实例化得到db对象
2 在app中注册
db.init_app(app)
3 表模型继承 db.Model
4 session是db.session
db.session使用即可
存在问题
1 表迁移麻烦
2 不支持字段的动态修改
flask-migrate使用(就和插件差不多了)
像djagno一样,执行两条迁移命令,实现数据库的动态迁移
pip install flask-migrate
使用步骤
第一步:from flask_migrate import Migrate, MigrateCommand
第二步:执行
Migrate(app, db)
manager.add_command('db', MigrateCommand)
python3 manage.py db init 初始化:只执行一次,生成一个migrations文件夹
以后直接在model.py里面新建表,新建字段,执行命令,就会自动同步
python3 manage.py db migrate 等同于 makemigartions
python3 manage.py db upgrade 等同于migrate
接口幂等性
接口幂等性:http://www.liuqingzheng.top/article/1/01-%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%B9%82%E7%AD%89%E6%80%A7/
幂等性:多次操作,做的改变是一样的
新增接口--》执行了3次,出现3条记录,这就不是幂等性的接口
get,delete,update 都是幂等性 (查一次跟查10次是没有区别的,删除1次跟删10次也是没有区别的)
post:是不幂等的;存在问题,就是说是用户真的想创建两个订单,还是不小心点了两次
如果要保证幂等,使用token机制(只要访问之前,先拿一个token值,放在redis里面。想要创建,必须携带这个token,创建完,把redis删除。下次再带同样的token过来,redis里面没有了
就代表消费过了,就不能再创建这个订单了)
云原生:
云:云服务器(公有云:阿里,华为,私有云:公司自己的服务器)
原生:使用编程语言写的程序(go,python,java写了程序)
把这些程序,跑在云上,就叫云原生
云原生的组件:docker,k8s,jenkins,gitlab。。。。(主要指的是k8s)
云存储
就是存储文件的服务器,是集群架构的
公有云存储:七牛云,阿里oss
私有云存储:fastdfs,ceph,minio。。
paas,saas,iaas(云服务的模型)
SaaS(软件即服务):假设要搞一个电商,之前是要招开发,开发完部署,上线使用。现在是直接买软件,软件也跑在软件公司的服务器上,不需要部署在客户现场。就是直接买软件
PaaS(平台即服务):云平台,阿里云就是paas,买云服务器,上面改装的软件都装好了,我只需要把我的服务跑在上面
IaaS(基础架构即服务):买服务器的厂商,你买了之后,自己组装,装上软件,自己跑
serverless:无服务
现在公司要干这个事,直接用别人的
敏捷开发
敏捷开发的一个sprint
devops ,sre
其实是一个概念,不同公司提出来的
运维+开发 保证云平台稳定运行---》sre,devops
ci cd jenkins+gitlab+docker
持续集成
持续部署
微服务
服务拆分----》分布式的子集
中间件
组件:
消息队列中间件:rabbitmq,kafka
数据库中间件(程序和数据库之间:做一些分库分表的):mycat
服务器中间件(程序和服务之间的一个东西):nginx,kong---》api网关
缓存中间件:redis
DDD:领域驱动设计
只是一个概念
核心的逻辑写在数据层
回顾
1、sqlalchemy orm框架
单表
一对多
一对一,是一对多的特殊情况
Person Hobby两张表,一对多的关系一旦确立,外键字段写在多的一方
就是为了模拟出django的orm中基于对象的跨表查询,直接点hobby就能点出hobby对象来
多对多:需要建中间表
表中除了需要id之外,还需要记录额外的信息,这时就必须手动创建第三张表了
中间表里其实就是跟第一个表和第二个表做一个外键关联
2、sqlalchemy
不能创建库,不能修改字段
3、flask-sqlalchemy
直接用的话,一步一步的用,但是框架又帮我们封装了一下,实例化得到一个对象
使用步骤
1 导入from flask_sqlalchemy import SQLAlchemy 实例化得到db对象
2 在app中注册
db.init_app(app)
3 表模型继承 db.Model
4 session是db.session
db.session使用即可
Sqlalchemy---》db.session和db.Model
配置信息配置在配置文件中
4、现在创建表,修改表,创建字段。比较麻烦,于是就有了flask-migrate
flask-migrate :基于flask-script
flask-script 自定义命令
flask-migrate借助于flask-script创建了一个db命令
python3 manage.py db init 执行一次--》
python3 manage.py migrate 记录
python3 manage.py upgrade 同步到数据库