You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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')
验证方法
  1. 去Discord开发者后台,给机器人开启Message Content Intent、Guilds、Guild Messages、Guild Message Reactions这几个intents,不然机器人收不到消息和反应。
  2. 把代码里的YOUR_DISCORD_BOT_TOKEN换成你自己的令牌。
  3. 运行机器人,加入语音频道后发!assign,选一个表情,然后用数据库浏览器打开data.db,就能看到插入的数据了。

内容的提问来源于stack exchange,提问作者Hurai Geran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 11:52:31