← Back to course

PostgreSQL и приложения: подключаем базу данных к реальным проектам

PostgreSQL и приложения: подключаем базу данных к реальным проектам

Возвращаемся к PostgreSQL.

В предыдущем уроке ты создал маленькую базу данных для магазина.

Ты создал:

customers
categories
products
orders
order_items

Ты использовал:

Очень хорошо.

Теперь PostgreSQL — это уже не просто загадочное существо из терминала.

Он становится настоящим инструментом.

Но остаётся один очень важный вопрос:

Как приложение реально подключается к PostgreSQL?

Потому что в реальных проектах пользователи не открывают psql и не пишут SQL вручную.

Обычно.

Backend-приложение подключается к базе данных.

Потом приложение читает данные.

Записывает данные.

Обновляет данные.

Удаляет данные.

Надеемся, не все данные.

Потому что это был бы очень драматичный вторник.

Сегодня мы изучим, как приложения подключаются к PostgreSQL.

Этот урок не про один конкретный framework.

Эти идеи подходят для:

Django
Spring Boot
Node.js
Express
NestJS
Laravel
Rails
Go-приложений
любого backend, которому нужен PostgreSQL

Framework-и меняются.

Принципы подключения остаются.

Очень полезно.

Очень база данных.

Очень “пожалуйста, не пиши пароль прямо в коде”.

Что ты изучишь

В этом уроке ты изучишь:

К концу этого урока ты поймёшь мост между PostgreSQL и backend-приложениями.

Потому что база данных без приложения полезна.

Но база данных, подключённая к приложению, становится мощной.

Как склад, подключённый к магазину.

Или как кофемашина, подключённая к уставшему разработчику.

Важная инфраструктура.

Базовая идея

Приложению нужна информация для подключения, чтобы говорить с PostgreSQL.

Обычно нужны:

host
port
название базы данных
username
password

Пример:

host: localhost
port: 5432
database: shop_db
username: shop_user
password: strong_password

Приложение использует эти значения, чтобы открыть подключение.

Потом оно может отправлять SQL-запросы.

Например:

SELECT * FROM products;

Приложение отправляет запрос.

PostgreSQL выполняет его.

PostgreSQL возвращает результат.

Приложение использует результат.

Возможно, показывает продукты на сайте.

Возможно, создаёт API-ответ.

Возможно, генерирует отчёт.

Возможно, ломается, потому что кто-то забыл точку с запятой.

Классика.

Host PostgreSQL

Host говорит приложению, где работает PostgreSQL.

Для локальной разработки host часто такой:

localhost

или:

127.0.0.1

Это означает:

PostgreSQL работает на той же машине, что и приложение.

Пример:

host=localhost

В production PostgreSQL может работать на другом сервере.

Пример:

host=db.example.com

или:

host=10.0.0.5

или внутри Docker:

host=postgres

Host зависит от того, где живёт база данных.

Приложение должно знать правильный адрес.

Иначе оно будет стучать не в ту дверь.

PostgreSQL не ответит из дома, где он не живёт.

Очень логично.

Port PostgreSQL

PostgreSQL обычно слушает порт:

5432

Поэтому типичное подключение использует:

port=5432

Порт — это как номер двери на сервере.

Сервер может запускать много сервисов.

PostgreSQL по умолчанию использует порт 5432.

Если ты изменил порт, нужно использовать новый.

Но для начинающих в большинстве случаев ответ такой:

5432

Редкий момент простоты.

Наслаждайся.

Название базы данных

Один сервер PostgreSQL может содержать много баз данных.

Например:

learning_postgresql
shop_db
portfolio_db
blog_db

Твоё приложение должно знать, какую базу использовать.

Пример:

database=shop_db

Если приложение подключится к неправильной базе, начнутся странные вещи.

Таблиц может не быть.

Данные могут выглядеть старыми.

Твой мозг может начать debug не той вселенной.

Всегда проверяй название базы данных.

Маленькая ошибка.

Большая головная боль.

Username и password

PostgreSQL использует пользователей и пароли для контроля доступа.

Пример:

username=shop_user
password=strong_password

Пользователь определяет, что приложение может делать.

Пользователь может иметь права на:

подключение к базе данных
чтение таблиц
добавление строк
обновление строк
удаление строк
создание таблиц

Не давай каждому приложению полные права superuser.

Это как дать ребёнку бензопилу, потому что он хотел разрезать лист бумаги.

Технически эффективно.

Глубоко неразумно.

Не используй пользователя postgres в приложениях

PostgreSQL часто имеет административного пользователя по умолчанию:

postgres

Этот пользователь мощный.

Очень мощный.

Слишком мощный для обычных приложений.

Не используй postgres как пользователя своего приложения.

Вместо этого создай отдельного пользователя для приложения.

Пример:

shop_user
blog_user
app_user
portfolio_user

Почему?

Потому что если приложение имеет bug или его атакуют, ты хочешь ограничить ущерб.

Пользователь приложения должен иметь только те права, которые ему нужны.

Не ключи от всего королевства.

В королевстве базы данных есть драконы.

И счета.

Создаём базу данных для приложения

Открой PostgreSQL как пользователь postgres:

sudo -iu postgres psql

Создай базу данных:

CREATE DATABASE shop_db;

Создай пользователя:

CREATE USER shop_user WITH PASSWORD 'change_this_password';

Дай пользователю доступ к базе:

GRANT CONNECT ON DATABASE shop_db TO shop_user;

Теперь подключись к базе:

\c shop_db

Дай права на schema public:

GRANT USAGE ON SCHEMA public TO shop_user;

Разреши пользователю работать с таблицами:

GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO shop_user;

Разреши пользователю использовать sequences.

Это важно для SERIAL ID.

GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO shop_user;

Для будущих таблиц можно установить default privileges:

ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO shop_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO shop_user;

Это уже намного лучше, чем использовать superuser postgres.

Приложение получает доступ.

Но не безграничную власть.

Очень цивилизованно.

Тестируем нового пользователя

Выйди из PostgreSQL:

\q

Теперь попробуй подключиться как новый пользователь:

psql -h localhost -U shop_user -d shop_db

PostgreSQL попросит пароль.

Введи пароль, который ты создал.

Если подключение работает, ты попадёшь в psql.

Потом проверь:

SELECT current_user;

Ты должен увидеть:

shop_user

Хорошо.

Теперь твоё приложение тоже может использовать этого пользователя.

Дверь базы данных открывается.

Но только правильным ключом.

Очень безопасно.

Очень взросло.

Что такое connection string?

Connection string собирает всю информацию для подключения в одну строку.

Типичный формат PostgreSQL:

postgresql://username:password@host:port/database

Пример:

postgresql://shop_user:change_this_password@localhost:5432/shop_db

Он содержит:

username: shop_user
password: change_this_password
host: localhost
port: 5432
database: shop_db

Многие инструменты и framework-и используют connection string.

Они компактные.

Полезные.

И опасные, если их вставлять везде.

Потому что они содержат пароли.

Относись к connection string как к ключам.

Не публикуй их.

Не commit их на GitHub.

Не отправляй случайным людям.

Не вставляй их в screenshots.

Будущий ты скажет спасибо.

Люди из безопасности тоже перестанут кричать.

Переменные окружения

Приложения обычно читают настройки базы данных из переменных окружения.

Переменные окружения — это значения, которые хранятся вне кода.

Пример:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=shop_db
DB_USER=shop_user
DB_PASSWORD=change_this_password

Или:

DATABASE_URL=postgresql://shop_user:change_this_password@localhost:5432/shop_db

Зачем использовать переменные окружения?

Потому что код не должен содержать секреты.

Плохо:

пароль прямо в source code

Хорошо:

пароль в переменной окружения

Это позволяет использовать разные настройки для:

локальной разработки
тестов
production

Тот же код.

Другая конфигурация.

Очень полезно.

Очень профессионально.

Очень “я научился после болезненных ошибок”.

Файл .env

Во время локальной разработки многие проекты используют файл .env.

Пример:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=shop_db
DB_USER=shop_user
DB_PASSWORD=change_this_password

Или:

DATABASE_URL=postgresql://shop_user:change_this_password@localhost:5432/shop_db

Приложение читает этот файл при запуске.

Важно:

Не commit файлы .env с реальными паролями.

Добавь .env в .gitignore.

Пример .gitignore:

.env
.env.local
.env.production

Можно создать безопасный пример:

.env.example

Пример:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=shop_db
DB_USER=shop_user
DB_PASSWORD=your_password_here

Это показывает другим разработчикам, какие переменные нужны.

Но не раскрывает реальные секреты.

Хорошая практика.

Очень хорошая.

Золотая звёздочка.

Базоданная золотая звёздочка.

Пример: общие настройки приложения

Многим приложениям нужны такие настройки:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=shop_db
DB_USER=shop_user
DB_PASSWORD=change_this_password

Потом приложение создаёт подключение.

Концептуально:

Подключись к DB_HOST на DB_PORT.
Используй DB_NAME.
Войди с DB_USER и DB_PASSWORD.

Некоторые framework-и предпочитают один URL:

DATABASE_URL=postgresql://shop_user:change_this_password@localhost:5432/shop_db

Оба стиля распространены.

Какой использовать — зависит от framework.

Но идея одинаковая.

Твоему приложению нужны координаты базы данных.

Без координат оно бродит как турист со сломанным GPS.

Пример: Django settings

В Django настройки базы данных часто выглядят так:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "shop_db",
        "USER": "shop_user",
        "PASSWORD": "change_this_password",
        "HOST": "localhost",
        "PORT": "5432",
    }
}

Но писать пароль прямо здесь — плохая идея.

Лучше так:

import os

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": os.environ.get("DB_NAME"),
        "USER": os.environ.get("DB_USER"),
        "PASSWORD": os.environ.get("DB_PASSWORD"),
        "HOST": os.environ.get("DB_HOST", "localhost"),
        "PORT": os.environ.get("DB_PORT", "5432"),
    }
}

Теперь пароль приходит из переменных окружения.

Намного лучше.

Django получает данные для подключения.

Код остаётся безопаснее.

Все меньше нервничают.

Кроме, возможно, CSS-разработчика.

Но это уже другой курс.

Пример: Spring Boot settings

В Spring Boot application.properties может выглядеть так:

spring.datasource.url=jdbc:postgresql://localhost:5432/shop_db
spring.datasource.username=shop_user
spring.datasource.password=change_this_password

Лучше с переменными окружения:

spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASSWORD}

Тогда твоё окружение может содержать:

DB_URL=jdbc:postgresql://localhost:5432/shop_db
DB_USER=shop_user
DB_PASSWORD=change_this_password

Это намного безопаснее, чем hardcode секретов.

В реальных проектах пароль базы данных не должен жить в Git repository.

Git помнит всё.

Как слон.

Но с историей commit-ов.

Пример: Node.js connection

Node.js приложение может использовать connection string:

DATABASE_URL=postgresql://shop_user:change_this_password@localhost:5432/shop_db

Потом приложение читает его.

Концептуально:

const connectionString = process.env.DATABASE_URL;

Многие Node.js библиотеки поддерживают этот стиль.

Важная идея не в конкретной библиотеке.

Важная идея такая:

Читай секреты из переменных окружения.
Не hardcode их в коде.

Это правило идёт за тобой через все языки.

Python.

Java.

JavaScript.

Go.

PHP.

Везде.

Секреты в коде — как открытые окна зимой.

Плохая идея.

Потом дорого.

Локальная разработка vs production

Локальная разработка обычно означает:

приложение и база данных работают на твоём компьютере
host = localhost
port = 5432

Production обычно означает:

приложение работает на сервере
база данных может работать на другом сервере
host не localhost
пароль сильнее
безопасность важнее
backup-и важнее
monitoring важнее

В локальной разработке ошибки раздражают.

В production ошибки становятся счетами.

Очень мотивирует.

Именно поэтому конфигурация должна быть гибкой.

Ты можешь иметь:

локальную базу данных
тестовую базу данных
production базу данных

Каждое окружение имеет разные значения.

Тот же код приложения.

Разные переменные окружения.

Это нормально.

Это профессионально.

Так мы не меняем код только для того, чтобы подключиться куда-то иначе.

Docker и host names PostgreSQL

Если твоё приложение и PostgreSQL работают в Docker Compose, host часто является названием service.

Пример:

services:
  app:
    environment:
      DB_HOST: postgres
      DB_PORT: 5432

  postgres:
    image: postgres

Внутри Docker приложение может подключаться к:

postgres

а не к:

localhost

Почему?

Потому что внутри container приложения localhost означает сам container приложения.

Не PostgreSQL container.

Это очень частая ошибка.

Очень частая.

Очень болезненная.

Очень Docker.

Простое правило:

С твоего компьютера: localhost может работать.
Из другого container: используй название service.

Поэтому в Docker Compose host базы данных может быть:

postgres

или:

db

в зависимости от названия service.

Docker networking мощный.

И иногда остренький.

Типичные ошибки подключения

Connection refused

Пример ошибки:

connection refused

Обычно это означает:

PostgreSQL не запущен.
Неправильный host.
Неправильный port.
PostgreSQL не слушает там.
Firewall блокирует подключение.

Проверь статус PostgreSQL:

systemctl status postgresql

На некоторых системах название service может отличаться.

Также можно попробовать:

psql -h localhost -U shop_user -d shop_db

Если psql не может подключиться, твоё приложение, скорее всего, тоже не сможет.

Не обвиняй framework сразу.

Сначала проверь базу данных.

Framework-и часто виноваты.

Но не всегда.

Password authentication failed

Пример ошибки:

password authentication failed for user

Обычно это означает:

неправильный username
неправильный password
пользователя не существует
переменная окружения имеет неправильное значение

Проверь username:

SELECT current_user;

Проверь, существует ли пользователь:

\du

Если нужно, измени пароль:

ALTER USER shop_user WITH PASSWORD 'new_password_here';

Потом обнови переменную окружения.

Не обновляй только свою память.

Приложения не читают твою память.

К счастью.

Database does not exist

Пример ошибки:

database "shop_db" does not exist

Обычно это означает именно то, что написано.

Проверь базы данных:

\l

Создай базу, если нужно:

CREATE DATABASE shop_db;

Или исправь название базы в конфигурации.

Эта ошибка часто является просто typo.

Маленькое typo с большой личностью.

Permission denied

Пример ошибки:

permission denied for table products

Это означает, что пользователь успешно подключился.

Но не имеет прав сделать что-то.

Дай права:

GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO shop_user;

Для sequences:

GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO shop_user;

Если приложение может читать, но не может вставлять строки с SERIAL ID, проблема может быть в правах на sequences.

Права PostgreSQL мощные.

И немного раздражающие.

Как серьёзный охранник с бумагами.

Table does not exist

Пример ошибки:

relation "products" does not exist

Возможные причины:

Ты подключился к неправильной базе данных.
Таблица не создана.
Таблица в другой schema.
Migration не запущена.
Название таблицы другое.

Проверь таблицы:

\dt

Проверь текущую базу данных:

SELECT current_database();

Эта ошибка часто случается, когда приложение подключается к одной базе, а ты создал таблицы в другой.

Классика.

Болезненно.

Очень обучающе.

Базовые правила безопасности

Вот простые правила.

Не advanced security.

Базовое выживание.

Не hardcode пароли

Плохо:

пароль в source code

Хорошо:

пароль в переменной окружения

Код можно распространять.

Секреты — нет.

Очень просто.

Очень часто игнорируется.

Очень опасно.

Не commit .env

Добавь .env в .gitignore.

.env
.env.local
.env.production

Если ты случайно commit реальный пароль, измени его.

Не просто удаляй файл из последнего commit и не делай вид, что ничего не случилось.

Git history помнит.

Git в этой ситуации не твой друг.

Git — свидетель.

Используй отдельного пользователя базы данных

Не используй superuser postgres в приложении.

Создай app-specific user:

shop_user

Дай ему только нужные права.

Это ограничивает ущерб, если что-то пойдёт не так.

А что-то когда-нибудь пойдёт не так.

Это не пессимизм.

Это software development.

Используй сильные пароли

Не используй:

password
123456
postgres
admin
qwerty

Это не пароли.

Это приглашения.

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

Особенно в production.

Твоя база данных заслуживает лучшего.

Держи production database приватной

Production PostgreSQL database обычно не должна быть открыта для всего интернета.

Лучше:

private network
firewall rules
limited IP access
secure hosting configuration

Если база данных доступна публично, безопасность становится намного серьёзнее.

Базы данных любят приватность.

Пользователи тоже.

Юристы тоже.

Application migrations

Многие framework-и используют migrations.

Migration — это контролируемое изменение базы данных.

Примеры:

создать таблицу
добавить колонку
изменить тип колонки
создать индекс
удалить таблицу

Вместо того чтобы каждый раз вручную менять базу данных, framework отслеживает изменения.

Django имеет migrations.

Spring Boot часто использует Flyway или Liquibase.

Node.js ORM-и тоже имеют migration tools.

Идея такая:

Структура базы данных должна быть versioned.

Это важно, потому что приложение и база данных должны совпадать.

Если код ожидает колонку email, а база её не имеет, приложение ломается.

Очень уверенно.

Migrations помогают держать структуру под контролем.

Это не магия.

Но лучше, чем случайные ручные изменения в полночь.

ORM vs Raw SQL

Многие приложения используют ORM.

ORM означает Object-Relational Mapping.

Примеры:

Django ORM
Hibernate / JPA
Prisma
TypeORM
Sequelize
SQLAlchemy

ORM позволяет работать со строками базы данных как с объектами.

Пример идеи:

Product object
Customer object
Order object

ORM генерирует SQL.

Это удобно.

Но всё равно нужно понимать SQL.

Почему?

Потому что когда что-то становится медленным или ломается, ORM не спасёт твою душу.

Он сгенерирует SQL.

PostgreSQL выполнит SQL.

Проблемы производительности всё равно остаются SQL-проблемами.

Поэтому изучение SQL — это не пустая трата времени.

Даже если ты используешь ORM.

Особенно если ты используешь ORM.

Потому что теперь ты знаешь, что происходит под одеялом.

А иногда под одеялом живёт monster query.

Типичный flow приложения

Типичный backend flow выглядит так:

Пользователь открывает сайт.
Frontend отправляет request в backend.
Backend подключается к PostgreSQL.
Backend выполняет query.
PostgreSQL возвращает данные.
Backend возвращает JSON или HTML.
Frontend показывает результат.

Пример:

GET /products

Backend query:

SELECT
  p.id,
  p.name,
  p.price,
  c.name AS category_name
FROM products AS p
JOIN categories AS c
ON p.category_id = c.id
ORDER BY p.name;

Backend возвращает JSON:

[
  {
    "id": 1,
    "name": "Laptop",
    "price": 900.00,
    "category": "Electronics"
  }
]

Так PostgreSQL становится частью приложения.

Пользователь никогда не видит SQL.

Но SQL делает работу.

Как работник за кулисами.

Тихий.

Важный.

Немного недооценённый.

Connection pooling

Открыть подключение к базе данных занимает время.

Если каждый request открывает новое подключение и сразу закрывает его, производительность может пострадать.

Многие приложения используют connection pool.

Connection pool держит несколько открытых подключений к базе данных и повторно их использует.

Простая идея:

Не создавай новое подключение каждый раз.
Повторно используй существующие подключения.

Большинство framework-ов делает это за тебя.

Но хорошо знать идею.

Потому что production systems очень внимательно относятся к подключениям.

Слишком много подключений может перегрузить PostgreSQL.

Слишком мало подключений может замедлить приложение.

Баланс важен.

Как кофе.

Мало — плохо.

Много — и ты слышишь цвета.

Практика

Создай новую базу данных:

CREATE DATABASE app_demo_db;

Создай нового пользователя:

CREATE USER app_demo_user WITH PASSWORD 'change_this_password';

Дай право подключения:

GRANT CONNECT ON DATABASE app_demo_db TO app_demo_user;

Подключись к базе:

\c app_demo_db

Создай простую таблицу:

CREATE TABLE messages (
  id SERIAL PRIMARY KEY,
  title VARCHAR(150) NOT NULL,
  content TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Дай права на schema:

GRANT USAGE ON SCHEMA public TO app_demo_user;

Дай права на таблицы:

GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_demo_user;

Дай права на sequences:

GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_demo_user;

Добавь test row:

INSERT INTO messages (title, content)
VALUES ('Hello App', 'This row could be read by a backend application.');

Протестируй подключение:

psql -h localhost -U app_demo_user -d app_demo_db

Потом выполни:

SELECT * FROM messages;

Если это работает, у тебя есть база данных, пользователь, права и рабочее подключение.

Это фундамент интеграции с приложениями.

Не блестящий.

Очень важный.

Как хорошая электропроводка.

Никто её не видит.

Все жалуются, когда она не работает.

Мини-задание

Создай базу данных для blog application.

Требования:

database name: blog_app_db
user name: blog_app_user
tables: authors, posts

Правила:

Создай базу данных:

CREATE DATABASE blog_app_db;

Создай пользователя:

CREATE USER blog_app_user WITH PASSWORD 'change_this_password';

Дай право подключения:

GRANT CONNECT ON DATABASE blog_app_db TO blog_app_user;

Подключись:

\c blog_app_db

Создай таблицы:

CREATE TABLE authors (
  id SERIAL PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  name VARCHAR(100) NOT NULL
);
CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  author_id INTEGER NOT NULL REFERENCES authors(id),
  title VARCHAR(150) NOT NULL,
  content TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Дай права:

GRANT USAGE ON SCHEMA public TO blog_app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO blog_app_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO blog_app_user;

Создай полезные индексы:

CREATE INDEX idx_posts_author_id
ON posts(author_id);
CREATE INDEX idx_posts_created_at
ON posts(created_at);

Теперь создай .env.example файл для приложения:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=blog_app_db
DB_USER=blog_app_user
DB_PASSWORD=your_password_here

Или:

DATABASE_URL=postgresql://blog_app_user:your_password_here@localhost:5432/blog_app_db

Потом дай ответ:

Какие значения безопасно commit?
Какие значения должны оставаться секретными?
Почему .env должен быть ignored by Git?
Почему приложение не должно использовать пользователя postgres?

Это практично.

Это реально.

Это скучный фундамент, который предотвращает захватывающие катастрофы.

А в базах данных “скучно” часто означает “хорошо”.

Очень хорошо.

Типичные ошибки

Использовать postgres везде

Не делай этого.

Пользователь postgres нужен для администрирования.

Твоё приложение должно иметь собственного пользователя.

Дай ему только нужные права.

Это базовая безопасность.

Базовая безопасность не optional.

Это как носить обувь в мастерской.

Писать секреты в коде

Плохо:

spring.datasource.password=my_real_password

Плохо:

"PASSWORD": "my_real_password"

Плохо:

const password = "my_real_password";

Используй переменные окружения.

Твой код — не сейф.

Забывать права на sequences

Если приложение может вставлять строки, но падает с ошибками прав на sequences, помни:

GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_user;

SERIAL использует sequences.

Sequences требуют прав.

PostgreSQL точный.

Иногда болезненно точный.

Подключаться к неправильной базе данных

Всегда проверяй:

SELECT current_database();

Многие bugs — это просто:

Я создал таблицу в одной базе.
Моё приложение подключается к другой базе.

Это больно.

Но очень распространено.

Неправильно использовать localhost в Docker

В Docker Compose localhost из container приложения обычно означает container приложения.

Не container базы данных.

Используй название database service.

Пример:

postgres

или:

db

Docker не ошибается.

Он просто очень буквальный.

Как PostgreSQL.

Они, наверное, хорошо ладят.

Итог

Сегодня ты изучил:

Это важный урок.

Теперь ты понимаешь, как PostgreSQL подключается к реальным приложениям.

Здесь знание базы данных становится backend-силой.

База данных хранит правду.

Приложение использует правду.

Пользователь видит результат.

А где-то посередине разработчик надеется, что переменные окружения правильные.

Очень реально.

Очень профессионально.

Очень понедельнично.

Следующий урок

В следующем уроке мы поговорим про backups, restore и базовое обслуживание базы данных.

Потому что создать базу данных — хорошо.

Использовать базу данных — лучше.

Но иметь возможность восстановить данные после проблемы — бесценно.

Backups скучные.

До того дня, когда они спасают твою жизнь.

Тогда они становятся прекрасными.