🐛 Fix the issue of duplicate data being written to the database

This commit is contained in:
洛水居室 2023-03-15 16:53:26 +08:00
parent 6e3f7ce815
commit e2649f63ee
No known key found for this signature in database
GPG Key ID: C9DE87DA724B88FC

View File

@ -10,7 +10,7 @@ from genshin.models import BaseCharacter
from genshin.models import CalculatorCharacterDetails from genshin.models import CalculatorCharacterDetails
from pydantic import ValidationError from pydantic import ValidationError
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlmodel import SQLModel, Field, String, Column, Integer, BigInteger, select, DateTime, func, delete from sqlmodel import SQLModel, Field, String, Column, Integer, BigInteger, select, DateTime, func, delete, Index
from telegram.ext import ContextTypes from telegram.ext import ContextTypes
from core.basemodel import RegionEnum from core.basemodel import RegionEnum
@ -45,10 +45,13 @@ class CookiesNotFoundError(Exception):
class CharacterDetailsSQLModel(SQLModel, table=True): class CharacterDetailsSQLModel(SQLModel, table=True):
__tablename__ = "character_details" __tablename__ = "character_details"
__table_args__ = (dict(mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci"),) __table_args__ = (
Index("index_player_character", "player_id", "character_id", unique=True),
dict(mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci"),
)
id: Optional[int] = Field(default=None, sa_column=Column(Integer, primary_key=True, autoincrement=True)) id: Optional[int] = Field(default=None, sa_column=Column(Integer, primary_key=True, autoincrement=True))
player_id: int = Field(sa_column=Column(BigInteger(), primary_key=True)) player_id: int = Field(sa_column=Column(BigInteger()))
character_id: int = Field(sa_column=Column(BigInteger(), primary_key=True)) character_id: int = Field(sa_column=Column(BigInteger()))
data: Optional[str] = Field(sa_column=Column(String(length=4096))) data: Optional[str] = Field(sa_column=Column(String(length=4096)))
time_updated: Optional[datetime] = Field(sa_column=Column(DateTime, onupdate=func.now())) # pylint: disable=E1102 time_updated: Optional[datetime] = Field(sa_column=Column(DateTime, onupdate=func.now())) # pylint: disable=E1102
@ -61,7 +64,7 @@ class CharacterDetails(Plugin):
) -> None: ) -> None:
self.mysql = mysql self.mysql = mysql
self.redis = redis.client self.redis = redis.client
self.ttl = 60 * 60 * 3 self.ttl = 60 * 60 * 6
async def initialize(self) -> None: async def initialize(self) -> None:
def fetch_and_update_objects(connection): def fetch_and_update_objects(connection):
@ -108,18 +111,34 @@ class CharacterDetails(Plugin):
ttl = await self.redis.ttl(key) ttl = await self.redis.ttl(key)
if max_ttl is None or (0 <= ttl <= max_ttl): if max_ttl is None or (0 <= ttl <= max_ttl):
try: try:
uid, character_id = re.findall(r"\d+", key) player_id, character_id = re.findall(r"\d+", key)
except ValueError: except ValueError:
logger.warning("非法Key %s", key) logger.warning("非法Key %s", key)
continue continue
data = await self.redis.get(key) data = await self.redis.get(key)
str_data = str(data, encoding="utf-8") str_data = str(data, encoding="utf-8")
sql_data = CharacterDetailsSQLModel(
player_id=uid, character_id=character_id, data=str_data, time_updated=datetime.now()
)
async with AsyncSession(self.mysql.engine) as session: async with AsyncSession(self.mysql.engine) as session:
await session.merge(sql_data) statement = (
await session.commit() select(CharacterDetailsSQLModel)
.where(CharacterDetailsSQLModel.player_id == player_id)
.where(CharacterDetailsSQLModel.character_id == character_id)
)
results = await session.exec(statement)
sql_data = results.first()
if sql_data is None:
sql_data = CharacterDetailsSQLModel(
player_id=player_id, character_id=character_id, data=str_data, time_updated=datetime.now()
)
async with AsyncSession(self.mysql.engine) as session:
session.add(sql_data)
await session.commit()
else:
if sql_data.time_updated <= datetime.now() - timedelta(hours=2):
sql_data.data = str_data
sql_data.time_updated = datetime.now()
async with AsyncSession(self.mysql.engine) as session:
session.add(sql_data)
await session.commit()
@staticmethod @staticmethod
def get_qname(uid: int, character: int): def get_qname(uid: int, character: int):
@ -143,12 +162,6 @@ class CharacterDetails(Plugin):
self.get_qname(uid, character_id), detail.json(), ex=self.ttl + randint * 60 # 使用随机数防止缓存雪崩 self.get_qname(uid, character_id), detail.json(), ex=self.ttl + randint * 60 # 使用随机数防止缓存雪崩
) )
async def set_character_details_for_mysql(self, uid: int, character_id: int, detail: "CalculatorCharacterDetails"):
data = CharacterDetailsSQLModel(player_id=uid, character_id=character_id, data=detail.json())
async with AsyncSession(self.mysql.engine) as session:
await session.merge(data)
await session.commit()
async def get_character_details_for_mysql( async def get_character_details_for_mysql(
self, self,
uid: int, uid: int,