Давайте рассмотрим SQL запрос, который возвращает несколько записей из базы данных. Обновим метод SnippetModel.Latest()
, чтобы он возвращал десять последних заметок (при условии, что срок их действия не истёк).
Мы будем использовать следующий SQL запрос:
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
1 2 |
SELECT id, title, content, created, expires FROM snippets WHERE expires > UTC_TIMESTAMP() ORDER BY created DESC LIMIT 10 |
Откройте файл pkg/models/mysql/snippets.go
и обновите код для метода Latest()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
package mysql import ( "database/sql" "errors" "golangify.com/snippetbox/pkg/models" ) type SnippetModel struct { DB *sql.DB } ... // Latest - Метод возвращает последние 10 заметок. func (m *SnippetModel) Latest() ([]*models.Snippet, error) { // Пишем SQL запрос, который мы хотим выполнить. stmt := `SELECT id, title, content, created, expires FROM snippets WHERE expires > UTC_TIMESTAMP() ORDER BY created DESC LIMIT 10` // Используем метод Query() для выполнения нашего SQL запроса. // В ответ мы получим sql.Rows, который содержит результат нашего запроса. rows, err := m.DB.Query(stmt) if err != nil { return nil, err } // Откладываем вызов rows.Close(), чтобы быть уверенным, что набор результатов из sql.Rows // правильно закроется перед вызовом метода Latest(). Этот оператор откладывания // должен выполнится *после* проверки на наличие ошибки в методе Query(). // В противном случае, если Query() вернет ошибку, это приведет к панике // так как он попытается закрыть набор результатов у которого значение: nil. defer rows.Close() // Инициализируем пустой срез для хранения объектов models.Snippets. var snippets []*models.Snippet // Используем rows.Next() для перебора результата. Этот метод предоставляем // первый а затем каждую следующею запись из базы данных для обработки // методом rows.Scan(). for rows.Next() { // Создаем указатель на новую структуру Snippet s := &models.Snippet{} // Используем rows.Scan(), чтобы скопировать значения полей в структуру. // Опять же, аргументы предоставленные в row.Scan() // должны быть указателями на место, куда требуется скопировать данные и // количество аргументов должно быть точно таким же, как количество // столбцов из таблицы базы данных, возвращаемых вашим SQL запросом. err = rows.Scan(&s.ID, &s.Title, &s.Content, &s.Created, &s.Expires) if err != nil { return nil, err } // Добавляем структуру в срез. snippets = append(snippets, s) } // Когда цикл rows.Next() завершается, вызываем метод rows.Err(), чтобы узнать // если в ходе работы у нас не возникла какая либо ошибка. if err = rows.Err(); err != nil { return nil, err } // Если все в порядке, возвращаем срез с данными. return snippets, nil } |
Важно: Закрытие набора результатов с использованием
defer rows.Close()
является очень важным моментом. Пока набор результатов открыт, он будет поддерживать соединение с базовой базой данных открытым… поэтому, если в этом методе что-то пойдет не так и набор результатов не будет закрыт, это приведет к тому, что соединения с базой данных будет израсходовано в пустую.
Использование модели в обработчиках
Вернемся в файл cmd/web/handlers.go
и обновим обработчик home()
, таким образом, чтобы он вызвал метод SnippetModel.Latest()
который выведет на страницу последние 10 заметок из базы данных .
А пока, просто закомментируем код, относящийся к рендерингу шаблона. Сделаем это следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package main import ( "errors" "fmt" // "html/template" "net/http" "strconv" "golangify.com/snippetbox/pkg/models" ) func (app *application) home(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { app.notFound(w) return } s, err := app.snippets.Latest() if err != nil { app.serverError(w, err) return } for _, snippet := range s { fmt.Fprintf(w, "%v\n", snippet) } // files := []string{ // "./ui/html/home.page.tmpl", // "./ui/html/base.layout.tmpl", // "./ui/html/footer.partial.tmpl", // } // ts, err := template.ParseFiles(files...) // if err != nil { // app.serverError(w, err) // return // } // err = ts.Execute(w, nil) // if err != nil { // app.serverError(w, err) // } } ... |
Запускаем наше веб-приложение из терминала:
1 |
go run ./cmd/web |
Переходим на главную страницу http://127.0.0.1:4000 вы должны увидеть ответ, похожий на следующий:
У нас появились только 2 записи, хотя в базе данных у нас как минимум 4 заметок. Ниже вы можете увидеть содержимое таблицы snippets
:
1 2 3 4 5 6 7 8 9 10 |
mysql> SELECT id, title, expires FROM snippets; +----+---------------------------------------------+---------------------+ | id | title | expires | +----+---------------------------------------------+---------------------+ | 1 | Не имей сто рублей | 2022-01-27 13:09:34 | | 2 | Лучше один раз увидеть | 2022-01-27 13:09:40 | | 3 | Не откладывай на завтра | 2021-02-03 13:09:44 | | 4 | История про улитку | 2021-04-28 14:39:12 | +----+---------------------------------------------+---------------------+ |
Проверяем данные из столбика expires
и понимаем, что из за нашего SQL запроса, а именно WHERE expires > UTC_TIMESTAMP()
который понимается как «все записи срок которых еще не истёк». SQL функция UTC_TIMESTAMP()
возвращает текущую дату с точности до секунды.
Вот и получается, что записи с ID 3 и 4 имеют старый срок годности и они нам не видны на главной странице сайта на golang!
Я не знаю в какой год вы прочтете эту статью так, что я обновлю для вас срок годности записей с ID 1 и 2 до 2030 года. В архиве (папка SQL) будет свежая резервная копия базы данных, вы можете заменить её на свою. Пишу ваш текущий год в комментариях 🙂
Скачать исходный код
В конце каждого урока — мы публикуем архив с исходным кодом урока на текущий момент.
Скачать: snippetbox-21.zip
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
2024г
2024