Discord.py机器人无法向SQLite3数据库插入语音频道相关数据的问题求助
嘿,我帮你排查出了问题的核心,还有几个潜在的bug需要修复,以下是详细的分析和解决方案:
核心问题:数据库事务未提交
这是数据没插入的直接原因——SQLite默认需要手动调用conn.commit()来提交写操作(比如INSERT),你的测试代码里加了这一步,但机器人的反应事件里完全漏掉了!所有插入操作都只停留在内存里,根本没写入磁盘数据库。
其他需要修复的问题
除了提交事务,代码里还有几个坑会导致功能异常:
1. on_reaction_add的参数写错了
Discord.py的这个事件第二个参数是**user(单数)**,不是users(复数),这个错误会导致你无法正确过滤机器人的反应,甚至引发隐性报错。
2. 全局变量滥用会导致多用户冲突
你用了一堆全局变量(getid、getguild、Flist),如果两个用户同时发!assign,后面的用户会覆盖前面的变量值,最后插入数据库的会是最后一个用户的数据,完全不符合预期。我改成用字典把消息ID和对应的用户数据绑定,这样每个选择消息对应自己的数据。
3. 异常处理太宽泛
原来的try-except没指定具体异常,会掩盖很多问题(比如用户没在语音频道时,ctx.author.voice会是None,应该捕获AttributeError),我优化了异常处理,只捕获特定错误,还加了错误日志方便排查。
完整的修复代码
import sqlite3 import discord from discord.ext import commands bot = commands.Bot(command_prefix="!", intents=discord.Intents.all()) # 启动时初始化一次数据库连接,不要每次命令都重新连 conn = sqlite3.connect('data.db') c = conn.cursor() # 先确保表存在,避免第一次运行时表不存在的错误 c.execute('''CREATE TABLE IF NOT EXISTS channel_data (id TEXT, guild_id TEXT, theme TEXT)''') conn.commit() # 用字典存储消息ID和对应的语音频道、服务器ID,替代全局变量 reaction_msg_data = {} @bot.command() async def assign(ctx): try: # 先检查用户是否在语音频道 if not ctx.author.voice or not ctx.author.voice.channel: await ctx.send('Please join a channel first') return voice_id = str(ctx.author.voice.channel.id) guild_id = str(ctx.author.guild.id) # 构建嵌入消息 embed = discord.Embed(title="Please select a theme", color=0xff6868) embed.add_field(name="1. Lofi", value="Lofi", inline=False) embed.add_field(name="2. Gaming✨", value="NCS, EDM", inline=False) msg = await ctx.send(embed=embed) await msg.add_reaction("") await msg.add_reaction("✨") # 把消息ID和对应的数据存到字典里 reaction_msg_data[msg.id] = (voice_id, guild_id) except AttributeError: await ctx.send('Please join a channel first') except Exception as e: print(f"Assign command error: {e}") await ctx.send('Oops, something went wrong setting up the theme picker.') @bot.event async def on_reaction_add(reaction, user): # 忽略机器人自己的反应 if user.bot: return # 检查这个消息是不是我们的主题选择消息 msg_id = reaction.message.id if msg_id not in reaction_msg_data: return # 取出对应的数据,然后从字典里删掉,避免重复处理 voice_id, guild_id = reaction_msg_data.pop(msg_id) theme = None # 尝试删除选择消息 try: await reaction.message.delete() except: pass # 判断表情对应的主题 if str(reaction.emoji) == '': await reaction.message.channel.send(f"Set the theme to lo-fi. Channel id = {voice_id}") theme = '1' elif str(reaction.emoji) == '✨': await reaction.message.channel.send(f"Set the theme to NCS. Channel id = {voice_id}") theme = '2' # 如果主题有效,插入数据库并提交 if theme: try: c.execute("INSERT INTO channel_data (id, guild_id, theme) VALUES (?,?,?)", (voice_id, guild_id, theme)) conn.commit() # 重点!一定要提交事务 print(f"Successfully saved: {voice_id}, {guild_id}, {theme}") except Exception as e: print(f"Database error: {e}") await reaction.message.channel.send('Failed to save your theme choice to the database.') @bot.event async def on_ready(): print(f'Logged in as {bot.user}') # 替换成你的机器人令牌 bot.run('YOUR_DISCORD_BOT_TOKEN')
验证方法
- 去Discord开发者后台,给机器人开启
Message Content Intent、Guilds、Guild Messages、Guild Message Reactions这几个intents,不然机器人收不到消息和反应。 - 把代码里的
YOUR_DISCORD_BOT_TOKEN换成你自己的令牌。 - 运行机器人,加入语音频道后发
!assign,选一个表情,然后用数据库浏览器打开data.db,就能看到插入的数据了。
内容的提问来源于stack exchange,提问作者Hurai Geran
相关产品推荐
相关产品推荐

