mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
refactor(db): 修复异步连接池无界增长,并完成 SQLAlchemy 2.0 迁移与分层归位 (#6320)
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Float, JSON, Index, func, or_, select
|
||||
from sqlalchemy import Integer, String, Float, JSON, Index, delete, func, or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column
|
||||
|
||||
from app.db import db_query, db_update, Base, get_id_column, async_db_query
|
||||
from app.db import Base, async_db_query, db_query, db_update, execute_dml, get_id_column
|
||||
|
||||
|
||||
class SiteUserData(Base):
|
||||
@@ -14,45 +14,45 @@ class SiteUserData(Base):
|
||||
"""
|
||||
id = get_id_column()
|
||||
# 站点域名
|
||||
domain = Column(String)
|
||||
domain: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 站点名称
|
||||
name = Column(String)
|
||||
name: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 用户名
|
||||
username = Column(String)
|
||||
username: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 用户ID
|
||||
userid = Column(String)
|
||||
userid: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 用户等级
|
||||
user_level = Column(String)
|
||||
user_level: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 加入时间
|
||||
join_at = Column(String)
|
||||
join_at: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 积分
|
||||
bonus = Column(Float, default=0)
|
||||
bonus: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 上传量
|
||||
upload = Column(Float, default=0)
|
||||
upload: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 下载量
|
||||
download = Column(Float, default=0)
|
||||
download: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 分享率
|
||||
ratio = Column(Float, default=0)
|
||||
ratio: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 做种数
|
||||
seeding = Column(Float, default=0)
|
||||
seeding: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 下载数
|
||||
leeching = Column(Float, default=0)
|
||||
leeching: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 做种体积
|
||||
seeding_size = Column(Float, default=0)
|
||||
seeding_size: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 下载体积
|
||||
leeching_size = Column(Float, default=0)
|
||||
leeching_size: Mapped[Optional[float]] = mapped_column(Float, default=0)
|
||||
# 做种人数, 种子大小 JSON
|
||||
seeding_info = Column(JSON, default=dict)
|
||||
seeding_info: Mapped[Optional[Any]] = mapped_column(JSON, default=dict)
|
||||
# 未读消息
|
||||
message_unread = Column(Integer, default=0)
|
||||
message_unread: Mapped[Optional[int]] = mapped_column(Integer, default=0)
|
||||
# 未读消息内容 JSON
|
||||
message_unread_contents = Column(JSON, default=list)
|
||||
message_unread_contents: Mapped[Optional[Any]] = mapped_column(JSON, default=list)
|
||||
# 错误信息
|
||||
err_msg = Column(String)
|
||||
err_msg: Mapped[Optional[str]] = mapped_column(String)
|
||||
# 更新日期
|
||||
updated_day = Column(String, default=datetime.now().strftime('%Y-%m-%d'))
|
||||
updated_day: Mapped[Optional[str]] = mapped_column(String, default=datetime.now().strftime('%Y-%m-%d'))
|
||||
# 更新时间
|
||||
updated_time = Column(String, default=datetime.now().strftime('%H:%M:%S'))
|
||||
updated_time: Mapped[Optional[str]] = mapped_column(String, default=datetime.now().strftime('%H:%M:%S'))
|
||||
|
||||
__table_args__ = (
|
||||
Index('ix_siteuserdata_updated_day_id', 'updated_day', 'id'),
|
||||
@@ -62,14 +62,13 @@ class SiteUserData(Base):
|
||||
@classmethod
|
||||
@db_query
|
||||
def get_by_domain(cls, db: Session, domain: str, workdate: Optional[str] = None, worktime: Optional[str] = None):
|
||||
statement = select(cls).where(cls.domain == domain)
|
||||
if workdate and worktime:
|
||||
return db.query(cls).filter(cls.domain == domain,
|
||||
cls.updated_day == workdate,
|
||||
cls.updated_time == worktime).all()
|
||||
statement = statement.where(cls.updated_day == workdate,
|
||||
cls.updated_time == worktime)
|
||||
elif workdate:
|
||||
return db.query(cls).filter(cls.domain == domain,
|
||||
cls.updated_day == workdate).all()
|
||||
return db.query(cls).filter(cls.domain == domain).all()
|
||||
statement = statement.where(cls.updated_day == workdate)
|
||||
return list(db.execute(statement).scalars().all())
|
||||
|
||||
@classmethod
|
||||
@async_db_query
|
||||
@@ -80,12 +79,12 @@ class SiteUserData(Base):
|
||||
elif workdate:
|
||||
query = query.filter(cls.updated_day == workdate)
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
return list(result.scalars().all())
|
||||
|
||||
@classmethod
|
||||
@db_query
|
||||
def get_by_date(cls, db: Session, date: str):
|
||||
return db.query(cls).filter(cls.updated_day == date).all()
|
||||
return list(db.execute(select(cls).where(cls.updated_day == date)).scalars().all())
|
||||
|
||||
@classmethod
|
||||
@db_query
|
||||
@@ -94,21 +93,23 @@ class SiteUserData(Base):
|
||||
获取各站点最新一天的数据
|
||||
"""
|
||||
subquery = (
|
||||
db.query(
|
||||
select(
|
||||
cls.domain,
|
||||
func.max(cls.updated_day).label('latest_update_day')
|
||||
)
|
||||
.where(or_(cls.err_msg.is_(None), cls.err_msg == ""))
|
||||
.group_by(cls.domain)
|
||||
.filter(or_(cls.err_msg.is_(None), cls.err_msg == ""))
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 主查询:按 domain 和 updated_day 获取最新的记录
|
||||
return db.query(cls).join(
|
||||
subquery,
|
||||
(cls.domain == subquery.c.domain) &
|
||||
(cls.updated_day == subquery.c.latest_update_day)
|
||||
).order_by(cls.updated_time.desc()).all()
|
||||
return list(db.execute(
|
||||
select(cls).join(
|
||||
subquery,
|
||||
(cls.domain == subquery.c.domain) &
|
||||
(cls.updated_day == subquery.c.latest_update_day)
|
||||
).order_by(cls.updated_time.desc())
|
||||
).scalars().all())
|
||||
|
||||
@classmethod
|
||||
@async_db_query
|
||||
@@ -133,7 +134,7 @@ class SiteUserData(Base):
|
||||
(cls.domain == subquery.c.domain) &
|
||||
(cls.updated_day == subquery.c.latest_update_day)
|
||||
).order_by(cls.updated_time.desc()))
|
||||
return result.scalars().all()
|
||||
return list(result.scalars().all())
|
||||
|
||||
@classmethod
|
||||
@db_update
|
||||
@@ -146,19 +147,15 @@ class SiteUserData(Base):
|
||||
"""
|
||||
分批删除指定日期之前的站点用户快照。
|
||||
"""
|
||||
ids = [
|
||||
row[0]
|
||||
for row in db.query(cls.id)
|
||||
.filter(cls.updated_day < before_day)
|
||||
ids = db.execute(
|
||||
select(cls.id)
|
||||
.where(cls.updated_day < before_day)
|
||||
.order_by(cls.id.asc())
|
||||
.limit(limit)
|
||||
.all()
|
||||
]
|
||||
).scalars().all()
|
||||
if not ids:
|
||||
return 0
|
||||
deleted = (
|
||||
db.query(cls)
|
||||
.filter(cls.id.in_(ids))
|
||||
.delete(synchronize_session=False)
|
||||
return execute_dml(
|
||||
db, delete(cls).where(cls.id.in_(ids)),
|
||||
execution_options={"synchronize_session": False},
|
||||
)
|
||||
return deleted
|
||||
|
||||
Reference in New Issue
Block a user