我使用具有兩個個人資料影像的用戶的一對多模型。這個想法是在存盤兩個影像后發送一封電子郵件。對于這兩個上傳呼叫從前端并行發送到后端。
我遇到的問題是,這可能導致存盤兩個影像但檢查影像計數失敗的引發條件,因為每個呼叫都在其自己的請求范圍的會話/事務中運行。
我現在的問題是如何使用 Flask-Sqlalchemy 對并行執行的燒瓶請求可靠地執行影像計數檢查
class User(Mixins, db.Model):
__tablename__ = 'user'
first_name = db.Column(db.String(1000), unique=False, nullable=True)
surname = db.Column(db.String(1000), unique=False, nullable=True)
email = db.Column(db.String(120, collation='NOCASE'), unique=True, index=True, nullable=False)
images: {} = db.relationship('ProfileImage',
back_populates="user",
cascade='all,delete-orphan')
class ProfileImage(Mixins, db.Model):
__tablename__ = 'profile_image'
file_name = db.Column(db.String, unique=False, index=False, nullable=True)
mime_type = db.Column(db.String, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship("User", back_populates="images")
def file_upload(request, user_id: int, side: str) -> int:
try:
file = image_service.get_image_from_request(request, side)
if file and is_valid_mime_type(file.get('mime_type', None)):
user = user_service.load_user(user_id)
image = ProfileImage(side=side,
file_name=file.get('name', None),
mime_type='image/jpg',
created_at=datetime.utcnow(),
)
user.images.append(image)
db.session.add(user)
db.session.commit()
if len(user.images) ==2:
send_email(user)
return CREATED
except ValueError as e:
current_app.logger.error(repr(e))
return BAD_REQUEST
uj5u.com熱心網友回復:
如果可能的話,我會盡量避免這種檢查。請注意,他們也有可能同時發送一封電子郵件,這有時比根本不發送任何電子郵件還要糟糕。
...但是強制同步的一種方法是使用 ROW 鎖。您不能鎖定正在插入的行,但可以鎖定用戶的行。然后一個影像創建任務被迫等待另一個完成。這可能很難跟蹤,并且您不想到處鎖定,因此您應該將其作為最后的手段,但SELECT FOR UPDATE的作業方式如下:
# User's table row is locked until session is commited or rolled back.
user = session.query(User).filter(User.id == current_user_id).with_for_update().first()
# Or session.query(User).get(current_user_id, with_for_update=True)
# Manipulate the user's profile images.
user.images.append(new_profile_image)
# I'd use a direct query in case the user.images are not accurate for some reason.
image_count = session.query(func.count(ProfileImage.id)).filter(ProfileImage.user == user).scalar()
if image_count == 2:
send_email(user)
# Release user row lock and commit changes.
session.commit()
這迫使一個作家等到另一個作家提交。閱讀有關更新行鎖定的 postgresql 選擇和sqlalchemy 的 with_for_update 介面。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/451626.html
標籤:Python 烧瓶 sqlalchemy 烧瓶-sqlalchemy 烧瓶会话
