Создание приложения на Golang для работы с РЕД База Данных
Данный пример демонстрирует создание простейшей программы на языке программирования Go (Golang) с использованием стандартного пакета database/sql для работы с базами данных. Мы рассмотрим, как подключиться к базе данных, создать таблицу, добавить, обновить, удалить и получить данные из таблицы.
Что будет рассмотрено в примере?
В ходе разработки мы:
- Подключимся к базе данных RedDatabase (основана на Firebird).
- Создадим таблицу для хранения данных об альбомах.
- Выполним базовые операции CRUD (Create, Read, Update, Delete).
Какие инструменты и технологии используются?
- Язык программирования: Go (Golang).
- Пакет для работы с базой данных: database/sql и драйвер для RedDatabase — github.com/nakagami/firebirdsql.
- СУБД: RedDatabase.
- Операционная система: РЕД ОС.
Установка GoLang на операционную систему РЕД ОС
- Выполните в терминале команду для установки golang:
sudo dnf install golang
-
Проверьте успешность установки командой:
go versionЕсли установка прошла успешно, должна вывестись версия Go. В данном случае установлен golang версии 1.22

-
Установка golang tools
sudo go install -v golang.org/x/tools/gopls@latest -
Установка отладчика для Golang:
go install github.com/go-delve/delve/cmd/dlv@latestgo installgithub.com/go-delve
Установка и настройка VSCode для работы на языке GoLang
- Для удобной установки и последующих обновлений добавим новый репозиторий:
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo'
-
Обновим список пакетов:
sudo dnf check-update -
Теперь можно установить VSCode:
sudo dnf install code -
Запустить VSCode можно командой:
code -
Перейдите во вкладку Extensions и в поиске введите Go и установите дополнение.

Установка RedDatabase
-
Перейдите на сайт https://reddatabase.ru/ и скачайте РЕД Базу Данных 5 (Инсталлятор для Linux (x86_64))
-
Задайте файлу права на выполнение:

- Перейдите в папку загрузки и через нажатие правой кнопки мыши откройте терминал

-
Выполните команду и установите РЕД Базу Данных (для дальнейшего удобства задайте пароль системного администратора
masterkey).sudo ./rdb50-linux-x86_64-standard-5.0.1.bin -
Запустите RedDatabase (самый простой способ — запустить rdbserver через терминал /opt/RedDatabase/bin/rdbserver)
Создание первой программы
- Для начала нужно создать папку нашего проекта (он будет находиться в домашней директории)
mkdir ~/first_go_programm
- Откроем ее при помощи VS Code
code ~/first_go_programm
-
Создадим новую папку в проекте и назовем ее .vscode (в ней будут храниться скрипты для сборки и запуска проекта в VS Code).
-
В папке vscode создадим два файла launch.json и tasks.json
-
В папке проекта создадим файл main.go
-
Инициализируем модуль Go
go mod init first_go_programmтеперь структура вашего проекта должна выглядеть так:

-
В tasks.json запишем скрипт
{ "version": "2.0.0", "tasks": [ { "label": "Build Go Project", "type": "shell", "command": "go", "args": ["build", "-o", "${workspaceFolder}/bin/"], "group": { "kind": "build", "isDefault": false }, "problemMatcher": [], "detail": "Compile the Go project into a binary." }, { "label": "Clean Build", "type": "shell", "command": "rm", "args": ["-rf", "${workspaceFolder}/bin"], "group": "build", "problemMatcher": [], "detail": "Clean up the bin directory." } ] }Он будет выполнять 2 функции: собирать проект в папку bin и удалять собранные файлы.
-
launch.json
{ "version": "0.2.0", "configurations": [ { "name": "Launch Project", "type": "go", "request": "launch", "mode": "debug", "program": "${workspaceFolder}", "env": {}, "args": [] } ] }Этот скрипт нужен для удобного запуска проекта.
-
В main.go запишем
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
-
Теперь для сборки программы нажмите комбинацию клавиш Ctrl + Shift + B и в открывшемся окне выберите Build Go Project (тут вызывается наш скрипт сборки, который мы написали ранее)
-
После успешной сборки проекта должна появиться папка bin с бинарным файлом. Для запуска нажмите F5.
Работа с базой данных RedDatabase
-
Теперь создадим папку, в которой будут храниться базы данных, и установим для нее права, чтобы RedDatabase могла с ней взаимодействовать
mkdir /db sudo chown firebird /db -
Установим библиотеку для работы с базой данных RedDatabase для Go.
go get github.com/nakagami/firebirdsqlЭта команда автоматически загрузит библиотеку в проект и подключит все зависимости
-
Подключите библиотеку в main.go (теперь import должен выглядеть так)
import (
"database/sql"
"fmt"
"log"
_ "github.com/nakagami/firebirdsql"
)
- Напишем функцию для создания базы данных:
func createDatabase() error {
var n int
conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@[::1]:3050/db/test.fdb")
//если у вас RedDatabase использует ipv4,
//то надо писать sysdba:masterkey@localhost:3050/db/test.db
defer conn.Close()
conn.QueryRow("SELECT Count(*) FROM rdb$relations").Scan(&n)
fmt.Println("Relations count=", n)
return nil
}
Для создания БД нужно использовать firebirdsql_createdb в качестве драйвера соединения, после создания БД уже надо использовать firebirdsql
- Напишем функцию, которая будет создавать таблицу и заполнять ее данными:
func createAlbumTable(db *sql.DB) error {
// Запрос для удаления таблицы, если она существует
dropTableQuery := `
EXECUTE BLOCK AS
BEGIN
IF (EXISTS (SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'ALBUM')) THEN
EXECUTE STATEMENT 'DROP TABLE ALBUM';
END;`
// Запрос для создания таблицы
createTableQuery := `
CREATE TABLE ALBUM (
ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
TITLE VARCHAR(128) NOT NULL,
ARTIST VARCHAR(255) NOT NULL,
PRICE NUMERIC(5,2) NOT NULL
);`
// Запросы для вставки данных
insertQueries := []string{
`INSERT INTO ALBUM (TITLE, ARTIST, PRICE) VALUES ('Blue Train', 'John Coltrane', 56.99);`,
`INSERT INTO ALBUM (TITLE, ARTIST, PRICE) VALUES ('Giant Steps', 'John Coltrane', 63.99);`,
`INSERT INTO ALBUM (TITLE, ARTIST, PRICE) VALUES ('Jeru', 'Gerry Mulligan', 17.99);`,
`INSERT INTO ALBUM (TITLE, ARTIST, PRICE) VALUES ('Sarah Vaughan', 'Sarah Vaughan', 34.98);`,
}
// Выполнение запроса для удаления таблицы
if _, err := db.Exec(dropTableQuery); err != nil {
return fmt.Errorf("ошибка при удалении таблицы ALBUM: %w", err)
}
// Выполнение запроса для создания таблицы
if _, err := db.Exec(createTableQuery); err != nil {
return fmt.Errorf("ошибка при создании таблицы ALBUM: %w", err)
}
// Последовательное выполнение запросов для вставки данных
for _, query := range insertQueries {
if _, err := db.Exec(query); err != nil {
return fmt.Errorf("ошибка при вставке данных в таблицу ALBUM: %w", err)
}
}
fmt.Println("Таблица ALBUM успешно создана и данные добавлены.")
return nil
}
func main() {
// Строка подключения
connStr := "sysdba:masterkey@[::1]:3050/db/test.db"
//если у вас RedDatabase использует ipv4,
//то надо писать sysdba:masterkey@localhost:3050/db/test.db
// Подключение к базе данных
db, err := sql.Open("firebirdsql", connStr)
if err != nil {
log.Fatalf("Ошибка подключения к базе данных: %v", err)
}
defer db.Close()
// Проверка соединения
if err := db.Ping(); err != nil {
log.Fatalf("Не удалось подключиться к базе данных: %v", err)
}
// Создание таблицы ALBUM
if err := createAlbumTable(db); err != nil {
log.Fatalf("Ошибка выполнения: %v", err)
}
}
Обратите внимание, что у reddatabase должен быть доступ ко всем папкам по пути к базе данных, а иначе возникнет ошибка доступа.
- Теперь напишем функцию, которая будет обращаться к нескольким строкам нашей таблицы и выводить их
// Album представляет структуру записи в таблице ALBUM
type Album struct {
ID int
Title string
Artist string
Price float64
}
// Функция для поиска альбомов по имени исполнителя
func albumsByArtist(db *sql.DB, artist string) ([]Album, error) {
var albums []Album
// SQL-запрос для поиска альбомов
query := "SELECT ID, TITLE, ARTIST, PRICE FROM ALBUM WHERE ARTIST = ?"
rows, err := db.Query(query, artist)
if err != nil {
return nil, fmt.Errorf("ошибка выполнения запроса albumsByArtist %q: %v", artist, err)
}
defer rows.Close()
// Обработка результата
for rows.Next() {
var alb Album
if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
return nil, fmt.Errorf("ошибка сканирования строки albumsByArtist %q: %v", artist, err)
}
albums = append(albums, alb)
}
// Проверка ошибок при обработке строк
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("ошибка при обработке строк albumsByArtist %q: %v", artist, err)
}
return albums, nil
}
6.1. Параметры функции:
db *sql.DB: Подключение к базе данных, которое используется для выполнения запроса.artist string: Имя исполнителя, по которому выполняется поиск.
6.2. Объявление переменной albums:
- Это срез типа
Album, который будет содержать результаты запроса.
6.3. SQL-запрос:
- Запрос выбирает столбцы
ID,TITLE,ARTIST,PRICEиз таблицыALBUM, где ARTIST соответствует указанному имени.
6.4. Выполнение запроса:
- Используется метод
db.Queryдля выполнения запроса с параметром artist. - Параметр artist заменяет знак вопроса
?в запросе, что предотвращает инъекции SQL.
6.5. Отложенное закрытие rows:
defer rows.Close()гарантирует, что ресурсы, связанные с результатами запроса, будут освобождены после выхода из функции.
6.6. Цикл для обработки строк:
- Метод
rows.Next()перемещается по каждой строке результата. - Для каждой строки создаётся новая переменная типа
Album(alb), в которую записываются данные из столбцов.
6.7. Сканирование столбцов:
- Метод
rows.Scanсчитывает данные столбцов текущей строки и записывает их в поля структурыalb.
- Запрос для одной строки
// albumByID ищет альбом по заданному идентификатору.
func albumByID(db *sql.DB, id int) (Album, error) {
// Объект для хранения данных из возвращенной строки.
var alb Album
// Выполнение SQL-запроса.
query := "SELECT ID, TITLE, ARTIST, PRICE FROM ALBUM WHERE ID = ?"
row := db.QueryRow(query, id)
// Сканирование данных в поля структуры Album.
if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
if err == sql.ErrNoRows {
// Если строка не найдена, возвращается ошибка с понятным сообщением.
return alb, fmt.Errorf("albumByID %d: альбом с таким ID не найден", id)
}
// Возвращение ошибки в случае других проблем.
return alb, fmt.Errorf("albumByID %d: ошибка выполнения запроса: %v", id, err)
}
// Возвращение найденного альбома.
return alb, nil
}
7.1. Параметры:
db *sql.DB: Подключение к базе данных.id int: Идентификатор альбома, который нужно найти.
7.2. Объявление переменной alb:
- Создаётся переменная типа
Albumдля хранения результата запроса.
7.3 SQL-запрос:
- Выполняется SQL-запрос для поиска записи по идентификатору (
ID). - Используется параметр
?для предотвращения инъекций SQL. - Значение
idподставляется в запрос черезQueryRow.
7.4 QueryRow и Scan:
- Метод
QueryRowвозвращает объектsql.Row, представляющий одну строку результата. - Метод
Scanизвлекает данные из строки и записывает их в поля структурыalb.
7.5 Пример использования:
// Поиск альбома по ID.
id := 1
album, err := albumByID(db, id)
if err != nil {
log.Printf("Ошибка: %v", err)
} else {
fmt.Printf("Найден альбом: ID=%d, Title=%q, Artist=%q, Price=%.2f\n", album.ID, album.Title, album.Artist, album.Price)
}
-
Добавление данных
// Добавление нового альбома. newAlbum := Album{ Title: "The Modern Sound of Betty Carter", Artist: "Betty Carter", Price: 49.99, } albID, err := addAlbum(db, newAlbum) if err != nil { log.Fatalf("Ошибка добавления альбома: %v", err) } fmt.Printf("ID добавленного альбома: %v\n", albID)
8.1 Создание нового альбома:
- Заполняется структура
Albumс данными нового альбома.
8.2 Вызов addAlbum:
- Передаётся подключение к базе данных (
db) и структураnewAlbum. - Возвращается ID нового альбома.
8.3 Вывод результата:
- Если альбом успешно добавлен, выводится его ID.
- В случае ошибки программа завершает работу с описанием проблемы.
8.4 Пример использования:
// Добавление нового альбома.
newAlbum := Album{
Title: "The Modern Sound of Betty Carter",
Artist: "Betty Carter",
Price: 49.99,
}
albID, err := addAlbum(db, newAlbum)
if err != nil {
log.Fatalf("Ошибка добавления альбома: %v", err)
}
fmt.Printf("ID добавленного альбома: %v\n", albID)
-
Удаление данных
// deleteAlbumByID удаляет альбом с указанным ID из таблицы ALBUM. func deleteAlbumByID(db *sql.DB, id int) error { // Выполнение SQL-запроса для удаления записи. query := "DELETE FROM ALBUM WHERE ID = ?" result, err := db.Exec(query, id) if err != nil { return fmt.Errorf("deleteAlbumByID: ошибка выполнения DELETE для ID %d: %v", id, err) } // Проверка количества удалённых строк. rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("deleteAlbumByID: ошибка получения количества удалённых строк: %v", err) } // Если запись с указанным ID не найдена. if rowsAffected == 0 { return fmt.Errorf("deleteAlbumByID: запись с ID %d не найдена", id) } fmt.Printf("Альбом с ID %d успешно удалён.\n", id) return nil }
9.1 SQL-запрос:
- Используется
DELETE FROM ALBUM WHERE ID = ?для удаления записи с указаннымID.
9.2 Exec:
- Метод
Execвыполняет запросDELETE, используя параметрid.
9.3 Проверка количества удалённых строк:
- Метод
RowsAffectedвозвращает количество строк, затронутых запросом. - Если
RowsAffectedравно 0, значит, запись с указаннымIDне найдена.
9.4 Пример использования:
// Удаление альбома по ID.
idToDelete := 1
err = deleteAlbumByID(db, idToDelete)
if err != nil {
log.Printf("Ошибка удаления альбома: %v", err)
} else {
fmt.Printf("Альбом с ID %d успешно удалён.\n", idToDelete)
}
Пример программы
Перед компиляцией программы установите библиотеку для графического интерфейса
package main
import (
"database/sql"
"fmt"
"log"
"strings"
"github.com/andlabs/ui"
_ "github.com/nakagami/firebirdsql" // Драйвер для работы с Firebird
)
type Album struct {
ID int
Title string
Artist string
Price float64
}
func createDatabase() error {
var n int
conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@[::1]:3050/db/test.fdb")
defer conn.Close()
conn.QueryRow("SELECT Count(*) FROM rdb$relations").Scan(&n)
fmt.Println("Relations count=", n)
return nil
}
func createAlbumTable(db *sql.DB) error {
dropTableQuery := `
EXECUTE BLOCK AS
BEGIN
IF (EXISTS (SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'ALBUM')) THEN
EXECUTE STATEMENT 'DROP TABLE ALBUM';
END;`
createTableQuery := `
CREATE TABLE ALBUM (
ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
TITLE VARCHAR(128) NOT NULL,
ARTIST VARCHAR(255) NOT NULL,
PRICE NUMERIC(5,2) NOT NULL
);`
if _, err := db.Exec(dropTableQuery); err != nil {
return fmt.Errorf("ошибка при удалении таблицы ALBUM: %w", err)
}
if _, err := db.Exec(createTableQuery); err != nil {
return fmt.Errorf("ошибка при создании таблицы ALBUM: %w", err)
}
fmt.Println("Таблица ALBUM успешно создана.")
return nil
}
func addAlbum(db *sql.DB, alb Album) (int, error) {
query := "INSERT INTO ALBUM (TITLE, ARTIST, PRICE) VALUES (?, ?, ?)"
result, err := db.Exec(query, alb.Title, alb.Artist, alb.Price)
if err != nil {
return 0, fmt.Errorf("addAlbum: ошибка выполнения INSERT: %v", err)
}
id, err := result.LastInsertId()
if err != nil {
return 0, fmt.Errorf("addAlbum: ошибка получения ID вставленной строки: %v", err)
}
return int(id), nil
}
func getAllAlbums(db *sql.DB) ([]Album, error) {
var albums []Album
query := "SELECT ID, TITLE, ARTIST, PRICE FROM ALBUM"
rows, err := db.Query(query)
if err != nil {
return nil, fmt.Errorf("ошибка выполнения запроса getAllAlbums: %v", err)
}
defer rows.Close()
for rows.Next() {
var alb Album
if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
return nil, fmt.Errorf("ошибка сканирования строки getAllAlbums: %v", err)
}
albums = append(albums, alb)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("ошибка при обработке строк getAllAlbums: %v", err)
}
return albums, nil
}
func updateAlbum(db *sql.DB, id int, alb Album) error {
query := "UPDATE ALBUM SET TITLE = ?, ARTIST = ?, PRICE = ? WHERE ID = ?"
result, err := db.Exec(query, alb.Title, alb.Artist, alb.Price, id)
if err != nil {
return fmt.Errorf("updateAlbum: ошибка выполнения UPDATE для ID %d: %v", id, err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("updateAlbum: ошибка получения количества изменённых строк: %v", err)
}
if rowsAffected == 0 {
return fmt.Errorf("updateAlbum: запись с ID %d не найдена", id)
}
fmt.Printf("Альбом с ID %d успешно обновлён.\n", id)
return nil
}
func deleteAlbumByID(db *sql.DB, id int) error {
query := "DELETE FROM ALBUM WHERE ID = ?"
result, err := db.Exec(query, id)
if err != nil {
return fmt.Errorf("deleteAlbumByID: ошибка выполнения DELETE для ID %d: %v", id, err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("deleteAlbumByID: ошибка получения количества удалённых строк: %v", err)
}
if rowsAffected == 0 {
return fmt.Errorf("deleteAlbumByID: запись с ID %d не найдена", id)
}
fmt.Printf("Альбом с ID %d успешно удалён.\n", id)
return nil
}
func setupUI(db *sql.DB) {
mainWindow := ui.NewWindow("Album Manager", 600, 400, true)
mainWindow.SetMargined(true)
vbox := ui.NewVerticalBox()
vbox.SetPadded(true)
mainWindow.SetChild(vbox)
// Add Album Section
addAlbumBox := ui.NewGroup("Добавить альбом")
addAlbumBox.SetMargined(true)
addAlbumForm := ui.NewForm()
addAlbumForm.SetPadded(true)
addAlbumBox.SetChild(addAlbumForm)
titleEntry := ui.NewEntry()
artistEntry := ui.NewEntry()
priceEntry := ui.NewEntry()
addAlbumForm.Append("Название", titleEntry, false)
addAlbumForm.Append("Исполнитель", artistEntry, false)
addAlbumForm.Append("Цена", priceEntry, false)
addAlbumButton := ui.NewButton("Добавить альбом")
addAlbumButton.OnClicked(func(*ui.Button) {
title := titleEntry.Text()
artist := artistEntry.Text()
price := 0.0
fmt.Sscanf(priceEntry.Text(), "%f", &price)
alb := Album{Title: title, Artist: artist, Price: price}
id, err := addAlbum(db, alb)
if err != nil {
ui.MsgBoxError(mainWindow, "Ошибка", err.Error())
} else {
ui.MsgBox(mainWindow, "Успех", fmt.Sprintf("Альбом добавлен с ID %d", id))
}
})
addAlbumForm.Append("", addAlbumButton, false)
vbox.Append(addAlbumBox, false)
// View All Albums Section
viewAlbumsButton := ui.NewButton("Показать все альбомы")
viewAlbumsButton.OnClicked(func(*ui.Button) {
albums, err := getAllAlbums(db)
if err != nil {
ui.MsgBoxError(mainWindow, "Ошибка", err.Error())
return
}
var builder strings.Builder
for _, alb := range albums {
builder.WriteString(fmt.Sprintf("ID: %d, Название: %s, Исполнитель: %s, Цена: %.2f\n", alb.ID, alb.Title, alb.Artist, alb.Price))
}
ui.MsgBox(mainWindow, "Список альбомов", builder.String())
})
vbox.Append(viewAlbumsButton, false)
// Delete Album Section
deleteAlbumBox := ui.NewGroup("Удалить альбом")
deleteAlbumBox.SetMargined(true)
deleteAlbumForm := ui.NewForm()
deleteAlbumForm.SetPadded(true)
deleteAlbumBox.SetChild(deleteAlbumForm)
deleteIDEntry := ui.NewEntry()
deleteAlbumForm.Append("ID альбома", deleteIDEntry, false)
deleteAlbumButton := ui.NewButton("Удалить альбом")
deleteAlbumButton.OnClicked(func(*ui.Button) {
id := 0
fmt.Sscanf(deleteIDEntry.Text(), "%d", &id)
if err := deleteAlbumByID(db, id); err != nil {
ui.MsgBoxError(mainWindow, "Ошибка", err.Error())
} else {
ui.MsgBox(mainWindow, "Успех", fmt.Sprintf("Альбом с ID %d удалён", id))
}
})
deleteAlbumForm.Append("", deleteAlbumButton, false)
vbox.Append(deleteAlbumBox, false)
// Update Album Section
updateAlbumBox := ui.NewGroup("Обновить альбом")
updateAlbumBox.SetMargined(true)
updateAlbumForm := ui.NewForm()
updateAlbumForm.SetPadded(true)
updateAlbumBox.SetChild(updateAlbumForm)
updateIDEntry := ui.NewEntry()
updateTitleEntry := ui.NewEntry()
updateArtistEntry := ui.NewEntry()
updatePriceEntry := ui.NewEntry()
updateAlbumForm.Append("ID альбома", updateIDEntry, false)
updateAlbumForm.Append("Новое название", updateTitleEntry, false)
updateAlbumForm.Append("Новый исполнитель", updateArtistEntry, false)
updateAlbumForm.Append("Новая цена", updatePriceEntry, false)
updateAlbumButton := ui.NewButton("Обновить альбом")
updateAlbumButton.OnClicked(func(*ui.Button) {
id := 0
fmt.Sscanf(updateIDEntry.Text(), "%d", &id)
title := updateTitleEntry.Text()
artist := updateArtistEntry.Text()
price := 0.0
fmt.Sscanf(updatePriceEntry.Text(), "%f", &price)
alb := Album{Title: title, Artist: artist, Price: price}
if err := updateAlbum(db, id, alb); err != nil {
ui.MsgBoxError(mainWindow, "Ошибка", err.Error())
} else {
ui.MsgBox(mainWindow, "Успех", fmt.Sprintf("Альбом с ID %d обновлён", id))
}
})
updateAlbumForm.Append("", updateAlbumButton, false)
vbox.Append(updateAlbumBox, false)
// Main Window
mainWindow.OnClosing(func(*ui.Window) bool {
ui.Quit()
return true
})
mainWindow.Show()
}
func main() {
createDatabase()
connStr := "sysdba:masterkey@[::1]:3050/db/test.fdb"
db, err := sql.Open("firebirdsql", connStr)
if err != nil {
log.Fatalf("Ошибка подключения к базе данных: %v", err)
}
defer db.Close()
if err := createAlbumTable(db); err != nil {
log.Fatalf("Ошибка при создании таблицы: %v", err)
}
ui.Main(func() {
setupUI(db)
})
}
Если при компиляции программы вы получили ошибку:
# github.com/andlabs/ui
# [pkg-config --cflags -- gtk+-3.0]
Package gtk+-3.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing gtk+-3.0.pc'
to the PKG_CONFIG_PATH environment variable
Package 'gtk+-3.0', required by 'virtual:world', not found
то выполните команду:
sudo dnf install gtk3-devel
и пересоберите проект.
Заключение
В этом руководстве мы рассмотрели, как создать простейшую программу на языке Go для работы с базой данных RedDatabase в операционной системе РЕД ОС. Мы прошли через установку необходимых инструментов, настройку среды разработки, создание базы данных и реализацию операций CRUD (создание, чтение, обновление и удаление записей).
В дополнение к базовым операциям мы также добавили графический интерфейс с использованием библиотеки andlabs/ui, что позволяет работать с базой данных без необходимости ввода команд в терминале.
Дата последнего изменения: 14.09.2026
Если вы нашли ошибку, пожалуйста, выделите текст и нажмите Ctrl+Enter.