Задать вопрос
@dodrator

Как правильно запускать хранимые процедуры?

Чтобы использовать написанную хранимку её нужно сначала запустить (сохранить в БД) в go коде, затем можно вызывать её по имени процедуры. Go код выглядит примерно так и он запускает sql file с созданием хранимки:
// execute stored sql function
	script, err := ioutil.ReadFile("path/to/procedure.sql")
	if err != nil {
		log.Fprintf(os.Stderr, "Error reading SQL script file: %v\n", err)
	}
	_, err = db.Exec(context.Background(), string(script))
	if err != nil {
		log.Fprintf(os.Stderr, "Error executing SQL script: %v\n", err)
	}


Если этот кусок кода вписать в go функцию, то она будет срабатывать при каждом вызове функции, хотя хранимка будет сохранена в БД после первого вызова, т.е последующие вызовы будут просто заменять уже существующую процедуру в БД. Мне интересно, важно ли то, чтобы код создания хранимки запускался единожды? Если да, то как этого достичь?
  • Вопрос задан
  • 438 просмотров
Подписаться 2 Простой Комментировать
Решения вопроса 3
nikonor
@nikonor
Программист go, perl
либо добавить if not exists, но лучше почитать про goose (https://github.com/pressly/goose)
Ответ написан
mayton2019
@mayton2019
Bigdata Engineer
Обычно в проекте заводят отдельный модуль. Версионный контроль для БД. Можно на базе
liquibase или flyway. Можно на базе каких-то Go-технологий.

Но суть такова. Хранимка устанавливается синхронно с обновлением версии комплекса. Как
часть установочного pipeline. И далее из кода ты ее просто вызываешь по имени.
Ответ написан
Комментировать
uvelichitel
@uvelichitel Куратор тега Go
habrahabr.ru/users/uvelichitel
О каких хранимках идёт речь?
В postgres есть собственная метафора хранимок, скомпилированных и живущих на postgres сервере. В Go пакет стандартной библиотеки sql сделан кросс-sql-движковым и ближайший аналог это sql.Stmt https://pkg.go.dev/database/sql#Stmt (в документации есть примеры кода). Вы можете скомпилировать sql стейтмент единожды в контексте соединения или транзакции и использовать многократно и потоко-безопасно пока жив контекст. Это даёт выигрыш в производительности.
Если я правильно вопрос)
Наивный код
script, err := ioutil.ReadFile("path/to/procedure.sql")
if err != nil {
    log.Fprintf(os.Stderr, "Error reading SQL script file: %v\n", err)
}
stmt, err := db.PrepareContext(context.Background(), string(script)) //компилируем стейтмент как шаблон c плейсхолдерами аргументов
if err != nil {
	log.Fatal(err)
}
_, err = stmt.ExecContext(ctx, args) //применяем стейтмент к аргументам args... в контексте ctx
if err != nil {
    log.Fprintf(os.Stderr, "Error executing SQL script: %v\n", err)
}

Шаблон (path/to/procedure.sql) может выглядеть так
SELECT username FROM users WHERE id = ?
Вопросительный знак ? это плейсхолдер для аргумента
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@d-stream
Готовые решения - не подаю, но...
"запуск", а правильнее - выполнение stored procedures - это действие, которое существенно отличается от их "установки" aka компиляции. В том числе это требует совершенно разных прав. Компиляция процедур/функций - требует повышенных прав.

А то что описано в переводе [и немного утрируя] звучит как: "исполняемая программа на go, которая генерит исходник на go, компилирует его и выполняет"

В общем случае так не делают в проде. На олимпиадах и вирусописательстве - возможно.
Ответ написан
@darst
Посмотрите вот этот метод sync.Once. Он позволяет выполнить код только один раз в запущенной программе.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы