aiogram开发Bot出现SQLite数据未持久化及战斗函数异常求助
问题排查与解决方案
一、战斗函数无法运行的问题
你的fight函数存在多个语法与逻辑错误,逐一修正如下:
SQL语法错误
UPDATE语句中用==赋值是错误的,SQL标准赋值符号为=;同时WHERE子句中user_id = 'user_id '是硬编码字符串,没有使用传入的user_id变量,多余空格还会导致数据匹配失败。变量覆盖与逻辑错误
你直接覆盖了从profile查询到的damage变量,导致更新回数据库的是战斗计算后的伤害值而非原角色伤害,完全不符合战斗逻辑,应使用临时变量存储计算出的伤害。嵌套循环冗余
一个用户对应一条profile数据和一条mob数据,嵌套循环会导致重复执行更新操作,完全没必要,应分别查询单条数据处理。SQL注入风险
用f-string拼接SQL语句存在注入风险,且容易出现变量替换错误,必须使用参数化查询。
修正后的战斗函数代码
def fight(user_id: int): # 查询用户角色数据 profile_cursor = sql.execute("SELECT hp, damage, power, armor FROM profile WHERE user_id = ?", (user_id,)) profile_data = profile_cursor.fetchone() if not profile_data: print("用户角色数据不存在") return hp, user_damage, user_power, user_armor = profile_data # 查询怪物数据 mob_cursor = sql.execute("SELECT mob_id, hp_mob, damage_mob, power_mob, armor_mob FROM mob WHERE user_id = ?", (user_id,)) mob_data = mob_cursor.fetchone() if not mob_data: print("怪物数据不存在") return mob_id, mob_hp, mob_damage, mob_power, mob_armor = mob_data # 计算伤害(用临时变量存储,不覆盖原数据,同时避免负数伤害) player_take_damage = max(0, mob_power - user_armor) mob_take_damage = max(0, user_power - mob_armor) # 更新角色血量 new_hp = hp - player_take_damage sql.execute("UPDATE profile SET hp = ? WHERE user_id = ?", (new_hp, user_id)) # 更新怪物血量 new_mob_hp = mob_hp - mob_take_damage sql.execute("UPDATE mob SET hp_mob = ? WHERE user_id = ?", (new_mob_hp, user_id)) # 统一提交事务(无需每次更新都commit,一次提交更高效) db.commit() print(f"玩家受到伤害: {player_take_damage}") print(f"怪物受到伤害: {mob_take_damage}")
二、SQLite数据偶尔无法保存的问题
结合aiogram异步框架特性,问题根源通常在以下几点:
线程安全问题
SQLite默认不允许跨线程使用同一个连接,aiogram的异步任务可能运行在不同线程中,导致连接冲突。解决方法:- 创建连接时添加
check_same_thread=False参数:import sqlite3 db = sqlite3.connect("your_db.db", check_same_thread=False) - 更推荐使用
aiosqlite这类异步SQL库,适配aiogram的异步环境。
- 创建连接时添加
事务提交与异常处理
若代码中存在未捕获的异常,会导致事务无法正常提交甚至回滚。需添加异常捕获与回滚逻辑:try: # 执行SQL操作 sql.execute(...) db.commit() except Exception as e: db.rollback() print(f"数据库操作失败: {e}")连接复用问题
避免频繁创建和关闭数据库连接,建议全局复用同一个连接实例;若必须使用多连接,需确保每个连接独立提交事务。异步阻塞问题
同步SQLite操作会阻塞aiogram的异步事件循环,导致任务堆积,间接引发数据保存异常。改用aiosqlite实现异步数据库操作:import aiosqlite async def fight(user_id: int): async with aiosqlite.connect("your_db.db") as db: async with db.execute("SELECT hp, damage, power, armor FROM profile WHERE user_id = ?", (user_id,)) as cursor: profile_data = await cursor.fetchone() # 后续所有数据库操作前加await await db.execute("UPDATE profile SET hp = ? WHERE user_id = ?", (new_hp, user_id)) await db.commit()
内容的提问来源于stack exchange,提问作者Матвей Васильев
相关产品推荐
相关产品推荐

