Golang+PostgreSQL开发Telegram Bot时重复添加用户问题排查
问题分析与修复:Telegram机器人注册功能重复添加用户
问题根源
1. SQL拼接引发的类型安全问题
代码直接用fmt.Sprintf拼接SQL语句,未采用参数化查询,会导致:
- 若Telegram用户ID(int64)超出数据库
uuid字段的类型范围(比如字段是int而非bigint),插入数据会被截断,后续用完整ID查询时无法匹配到被截断的记录,进而重复插入。 - 存在SQL注入风险,同时无法利用PostgreSQL的类型校验机制。
2. 字段类型不匹配
如果users表的uuid字段定义为int(32位),而Telegram用户ID是64位整数,插入时会自动截断高位,导致存储的ID与实际用户ID不一致,IsUserInDB自然查不到对应记录。
3. 逻辑瑕疵(非核心问题,但需优化)
handleMessages中添加用户后直接return err(此时err为nil),逻辑不够清晰;且未处理添加用户时的主键冲突(后续若将uuid设为主键则会遇到)。
修复方案
第一步:修正数据库字段类型
确保users表的uuid字段为bigint,匹配Telegram用户ID的int64类型:
ALTER TABLE users ALTER COLUMN uuid TYPE bigint;
建议将uuid设为主键,从数据库层面杜绝重复插入:
ALTER TABLE users ADD PRIMARY KEY (uuid);
第二步:替换为参数化查询(核心修复)
永远不要用字符串拼接构建SQL,改用PostgreSQL的参数占位符($n格式)保证类型安全:
修复IsUserInDB函数
func IsUserInDB(uuid int64) (bool, error) { var exists bool query := "SELECT EXISTS(SELECT 1 FROM users WHERE uuid = $1);" err := Db.QueryRow(query, uuid).Scan(&exists) return exists, err }
修复AddUserToDB函数
func AddUserToDB(column string, row interface{}) error { query := fmt.Sprintf("INSERT INTO users (%s) VALUES ($1);", column) _, err := Db.Exec(query, row) return err }
第三步:优化消息处理逻辑
添加主键冲突处理,同时补充用户提示:
func (b *Bot) handleMessages(message *tgbotapi.Message) error { switch message.Text { case "register": exists, err := data.IsUserInDB(message.From.ID) if err != nil { return err } if !exists { err := data.AddUserToDB("uuid", message.From.ID) if err != nil { // 捕获PostgreSQL主键冲突错误(错误码23505) if pgErr, ok := err.(*pq.Error); ok && pgErr.Code == "23505" { msg := tgbotapi.NewMessage(message.Chat.ID, "你已经注册过了!") _, sendErr := b.bot.Send(msg) return sendErr } return err } // 注册成功提示 msg := tgbotapi.NewMessage(message.Chat.ID, "注册成功!") _, sendErr := b.bot.Send(msg) return sendErr } // 已注册提示 msg := tgbotapi.NewMessage(message.Chat.ID, "你已经注册过了!") _, err = b.bot.Send(msg) return err default: msg := tgbotapi.NewMessage(message.Chat.ID, "未知指令...") _, err := b.bot.Send(msg) return err } }
注:需导入
github.com/lib/pq包以捕获PostgreSQL错误码。
验证修复
- 执行数据库字段修改语句。
- 替换代码后重新编译运行。
- 重复发送
register指令,机器人将正确识别已注册用户,不再重复添加记录。
内容的提问来源于stack exchange,提问作者Alexander Turok
相关产品推荐
相关产品推荐

