@uvins_s

Как проверить наличие пользователя в БД?

Я разрабатываю телеграмм-бота на языке программирования Golang. Пока что его задача просто регистрировать пользователя в БД mysql после команды /start. Но я столкнулся с проблемой, бот добавляет одного и того же юзера если он пропишет /start. Я попытался как-то решить эту проблему, но не выходит. Вот код:
db := sqlConn()
	times := time.Now().Unix()

	_, err := db.Query("SELECT chat_id FROM telegram WHERE chat_id=?", chatID)

	if err != nil {
		fmt.Println("Пользователь уже есть в базе данных")

	} else {
		res, err := db.Prepare("INSERT INTO telegram (chat_id, username, timestamp) VALUES (?, ?, ?)")

		if err != nil {
			panic(err.Error())
		}

		_, err = res.Exec(chatID, userName, times)

		if err != nil {
			panic(err.Error())
		}

		defer db.Close()
	}

По идее всё должно работать всё так: мы в БД ищем пользователя по chat_id, если он есть, то ошибки соответственно нету, а значит что пользователь уже есть в БД. Но, если пользователя нет, то по идее должна появляться ошибка, которую мы обрабатываем и сохраняем пользователя в БД. Но проблема в том, что это не работает, пользователь добавляется сколько хочет. Вопрос в том как это решить?
  • Вопрос задан
  • 264 просмотра
Решения вопроса 1
@falconandy
1. Ни db.Query(), ни db.QueryRow() не возвращают ошибку sql.ErrNoRows, если не вернулось ни одной записи. Смотрите, например, Query for a single row. Можете попробовать пакет jmoiron/sqlx для более удобной работы с БД (например, Get).
2. defer db.Close() должна находиться повыше. И почитайте документацию, нужен ли вам этот вызов вообще.
3. Использование db.Prepare()возможно тоже излишне.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@12rbah
В целом подход с двумя запросами избыточный в данном случае, можете просто делать вставку и возвращать ошибку. Кидать панику не нужно, нужно вынести код в отдельный метод и возвращать ошибку, если нужно то потом анализируйте её.
Ответ написан
DollyPapper
@DollyPapper
У вас какая-то странная логика получилась.
_, err := db.Query("SELECT chat_id FROM telegram WHERE chat_id=?", chatID)

если этот запрос отработает без ошибок (в т.ч. если результат будет не пустой), то err будет = nil, следовательно выполнится блок else и создастся пользователь. Т.е. буквально, если уже есть такой пользователь, то вы создаете нового.
Вам нужно что-то типа
_, err := db.Query("SELECT chat_id FROM telegram WHERE chat_id=?", chatID)
if errors.Is(err, sql.ErrNoRows) {
// создаем пользователя
} else {
fmt.Println("Пользователь уже есть в базе данных")
}
Ответ написан
uvelichitel
@uvelichitel Куратор тега Go
habrahabr.ru/users/uvelichitel
По крайней мере в postgres можно обойтись внутренним механизмом sql, одним запросом:
db.Prepare("INSERT INTO telegram (chat_id, username, timestamp) VALUES (?, ?, ?) ON CONFLICT (chat_id) DO NOTHING")

без проверок двойным запросом уровня языка приложения.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы