flaskd的sqlalchemy的高级用法

flaskd的sqlalchemy的高级用法,最全面的sqlalchemy关键常用知识点总结

sqlalchemy的exist用法

判断是否存在

1
2
3
from sqlalchemy.sql import exists
session.query(User.name).filter(~exists().where(User.role_id == Role.id)).scalar()
结果返回 true 或者 false

sqlalchemy的func用法

from sqlalchemy.sql import func

• func.count:统计行的数量。
• func.avg:求平均值。
• func.max:求最大值。
• func.min:求最小值。
• func.sum:求和。

group_by 分组查询和过滤

session.query(User.gender,func.count(User.id)).group_by(User.gender).all()

result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all()

group_by 使用的是having 使用filter是不可以的

sqlalchemy使用 sql语句

1
2
3
4
5
stmt = text("SELECT name, id, fullname, nickname "
... "FROM users where name=:name")
stmt = stmt.columns(User.name, User.id, User.fullname, User.nickname)
session.query(User).from_statement(stmt).params(name='ed').all()
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]
1
2
3
4
5
6
7
8
9
10
from sqlalchemy import text
for user in session.query(User).filter(text("id<244")).order_by(text("id")).all():
print user.name




session.query(User).filter(text("id<:value and name=:name")).params(value=224,name='ed').order_by(User.id)

sesseion.query(User).from_statement(text("select * from users where name=:name")).(name='ed').all()

from_statement+text+params 可以使用原生sql语句进行查询

subquery子查询

1
2
stmt = session.query(User.city.label("city"),User.age.label("age")).filter(User.username=='李A').subquery()
result = session.query(User).filter(User.city==stmt.c.city,User.age==stmt.c.age).all()

子查询可以让多个查询变成一个查询,只要查找一次数据库,性能相对来讲更加高效一点。不用写多个sql语句就可以实现一些复杂的查询。那么在sqlalchemy中,要实现一个子查询,应该使用以下几个步骤:

sqlalchemy的label用法

用于subquery子查询或者是对单字段的查询

MySQL的事务隔离级别

Serializable 串行化,一个事务一个事务的执行

Repeatable read 可重复读,无论其他事务是否修改并提交了数据,在这个事务中看到的数据值始终不受其他事务影响

Read committed 读取已提交,其他事务提交了对数据的修改后,本事务就能读取到修改后的数据值

Read uncommitted 读取为提交,其他事务只要修改了数据,即使未提交,本事务也能看到修改后的数据值。

MySQL数据库默认使用可重复读( Repeatable read),而使用乐观锁的时候,如果一个事务修改了库存并提交了事务,那其他的事务应该可以读取到修改后的数据值,所以不能使用可重复读的隔离级别,应该修改为读取已提交Read committed。

乐观锁

乐观锁并不是真实存在的锁,而是在更新的时候判断此时的库存是否是之前查询出的库存,如果相同,表示没人修改,可以更新库存,否则表示别人抢过资源,不再执行库存更新。类似如下操作

来自 https://blog.csdn.net/hello_mumu/article/details/82253456
rom django.http import HttpResponse
from rest_framework.generics import GenericAPIView
from app01.models import GoodsInfo

class Goods(GenericAPIView):
“”” 购买商品 “””
def post(self, request):

# 获取请求头中查询字符串数据
goods_id = request.GET.get('goods_id')
count = int(request.GET.get('count'))

while True:
    # 查询商品对象
    goods = GoodsInfo.objects.filter(id=goods_id).first()
    # 获取原始库存
    origin_stock = goods.stock

    # 判断商品库存是否充足
    if origin_stock < count:
        return HttpResponse(content="商品库存不足", status=400)

    # 演示并发请求
    import time
    time.sleep(5)

    # 减少商品的库存数量,保存到数据库
    # goods.stock = origin_stock - count
    # goods.save()
    """ 使用乐观锁进行处理,一步完成数据库的查询和更新 """
    # update返回受影响的行数
    result = GoodsInfo.objects.filter(id=goods.id, stock=origin_stock).update(stock=origin_stock - count)
    if result == 0:
        # 表示更新失败,有人抢先购买了商品,重新获取库存信息,判断库存
        continue

    # 表示购买成功,退出 while 循环
    break

return HttpResponse(content="操作成功", status=200)

sqlalchemy悲观锁 with_for_update

业务中有个需求,就是可能会遇到并发读取某一行数据,然后修改这行数据,这时候就涉及到并发的锁了

比如:

address表有个user_id=3的字段的status如果为0则要update,为1则不需要,如果没有锁,当两个session同时访问到user_id为3的字段时,此时status都为0,那么两个session都会对数据库做一次update,这等于update了两次,那么怎么避免这种情况呢?就要用到with_for_update()方法了:

下面是session1的代码

session1:

addr = Address.query.filter_by(user_id=3).with_for_update().first
if addr.status == 0:
addr.status = 1
db.session.commit()
下面是session2的代码:

session2:

addr = Address.query.filter_by(user_id=3).with_for_update().first
if addr.status == 0:
addr.status = 1
db.session.commit()
那么当session1抢先拿到锁的时候,在执行到最后的commit之前,session2都会卡住,当session1释放锁,session2拿到锁之后,status已经改为1了.

注意一旦使用with_for_update,对于查询事件也是限制锁

relationship可以使用order_by 对多的一边进行排序

小伟科技 wechat
python爱好者公众号—每日学习python必备
欢迎打赏支持!