Давайте обновим недавно созданный метод SnippetModel.Insert() из файла pkg/models/mysql/snippets.go, чтобы он создавал новую запись в таблице snippets, и затем возвращал id типа integer для только что созданной записи.

Содержание статьи

Для этого требуется выполнить следующий SQL запрос к базе данных:

Премиум 👑 канал по Golang

Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎

Подписаться на канал

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК ЧАТ в Telegram

Обратите внимание, что в этом запросе мы используем знак ? для указания плейсхолдера для данных, которых требуется вставить в базу данных. Так как данные, которые мы будем использовать, в конечном итоге будут поступать к нам от пользователя из HTML формы, рекомендуется использовать плейсхолдеры вместо вставки данных напрямую в SQL запросе.

Если вы не будете использовать плейсхолдеры, то вы рискуете оставить уязвимость в виде SQL-инъекции.

Выполнение SQL запроса

Go предоставляет три различных метода для выполнения запросов к базе данных:

  • DB.Query() используется для SELECT запросов, которые возвращают несколько рядов данных из таблицы, например «все записи за сегодня«;
  • DB.QueryRow() используется для SELECT запросов, которые возвращают один ряд, например «только одну запись у которой ID = 10«;
  • DB.Exec() используется для операторов, которые не возвращают данные (вроде INSERT и DELETE). Добавление данных или их удаление из базы данных.

В нашем случае, подходящим инструментом будет DB.Exec(). Давайте перейдем к сути и посмотрим, как мы применим его в методе SnippetModel.Insert(). Подробности разберем чуть позже.

Откройте файл pkg/models/mysql/snippets.go и обновите его следующим образом:

Давайте быстро разберем интерфейс sql.Result, который мы получаем после выполнения DB.Exec(). Он предоставляет два метода:

  • LastInsertId() возвращает целое число (int64), сгенерированное базой данных в ответ на выполненную команду вставки. Обычно это происходит в столбце id с «автоматическим инкрементом» при создании новой записи. Это наш случай;
  • RowsAffected() возвращает количество строк (в виде int64), которые были как-то затронуты (изменены) после выполненных действий.

Важно: Не все драйверы и базы данных поддерживают методы LastInsertId() и RowsAffected(). Например, LastInsertId() не поддерживается в PostgreSQL. Если вы планируете использовать данные методы, то нужно сначала проверить документацию для вашего драйвера.

Но, лучше всего игнорировать возвращаемое значение из sql.Result, если оно вам не нужно. Делается это таким образом:

Использование модели базы данных в обработчиках

Давайте вернемся к чему-то более конкретному и продемонстрируем, как вызывать методы моделей из наших обработчиков. Откройте файл cmd/web/handlers.go и обновите обработчик createSnippet следующим образом:

Запустите веб-приложение из терминала:

Затем откройте второе окно терминала и используйте curl, чтобы сделать запрос POST /snippet/create. Обратите внимание, что флаг -L указывает curl на автоматическое выполнение перенаправления. Наше приложение в конце выполняет редирект на страницу заметки.

Результат:

Все работает довольно хорошо. Мы только что отправили HTTP запрос, который запустил обработчик createSnippet, который вызвал метод SnippetModel.Insert(). Он вставил новую запись в базу данных и вернул ID этой новой записи. Затем обработчик перенаправил на другой адрес с ID в конце URL строки.

Можете взглянуть на содержимое таблицы snippets из базы данных MySQL.

Зайдите в MySQL через терминал:

Используйте пароль который вы указали при установки MySQL.

Выбираем базу данных:

Выполняем SELECT запрос, чтобы получить весь список заметок из таблицы:

Результат:

Вот и наша запись в конце под номером 4.

Использования плейсхолдеров для SQL запросов

В приведенном выше коде мы составили SQL запрос, используя плейсхолдеры, где знак ? выступал в качестве плейсхолдера для данных, которые требуется вставить.

Топорный перевод для плейсхолдера будет «придержи мне место» под будущие данные.

Причина использования плейсхолдера для построения запроса (а не интерполяции строк) заключается в том, что любые данные которые нужно вставить в базу данных нужно сперва «подготовить» прежде чем выполнить запрос. Даже если пользователь вместо заголовка заметки отправит какой-то вредоносный SQL запрос (SQL инъекция), то используя плейсхолдеры, эти запросы не навредят базе данных.

Под «капотом», метод DB.Exec() работает в три этапа:

  1. Он создает новый подготовленный запрос в базу данных, используя предоставленный SQL оператор. База данных парсирует и компилирует запрос, а затем хранит его готовым к выполнению;
  2. На втором шаге, Exec() передает значения параметров в базу данных. Затем база данных выполняет подготовленный запрос, используя эти параметры. Параметры передаются позже, поэтому после компиляции запроса, база данных рассматривает их как чистые данные. Они не могут изменить цель оператора. До тех пор, пока исходный оператор получен из ненадежных данных, инъекция не может произойти;
  3. Затем он закрывает подготовленный запрос к базе данных.

Синтаксис параметра плейсхоледера различается в зависимости от базы данных. MySQL, SQL Server и SQLite используют символ ?, но PostgreSQL использует $N. К примеру , если бы вы использовали PostgreSQL, вы бы создали запись таким образом:

Исходный код

В конце каждого урока мы предоставляем актуальный код на момент написания данной статьи.

Скачать: snippetbox-19.zip