PostgreSQL і застосунки: підключаємо базу даних до реальних проєктів

Повертаємось до PostgreSQL.
У попередній лекції ти створив маленьку базу даних для магазину.
Ти створив:
customers
categories
products
orders
order_items
Ти використовував:
- первинні ключі;
- зовнішні ключі;
JOIN;- агрегатні функції;
- індекси;
- мислення реального проєкту.
Дуже добре.
Тепер PostgreSQL — це вже не просто загадкова істота з терміналу.
Він стає реальним інструментом.
Але залишається одне дуже важливе питання:
Як застосунок реально підключається до PostgreSQL?
Бо в реальних проєктах користувачі не відкривають psql і не пишуть SQL вручну.
Зазвичай.
Backend-застосунок підключається до бази даних.
Потім застосунок читає дані.
Записує дані.
Оновлює дані.
Видаляє дані.
Сподіваємось, не всі дані.
Бо це був би дуже драматичний вівторок.
Сьогодні ми вивчимо, як застосунки підключаються до PostgreSQL.
Ця лекція не про один конкретний framework.
Ці ідеї підходять для:
Django
Spring Boot
Node.js
Express
NestJS
Laravel
Rails
Go-застосунків
будь-якого backend, якому потрібен PostgreSQL
Framework-и змінюються.
Принципи підключення залишаються.
Дуже корисно.
Дуже база даних.
Дуже “будь ласка, не пиши пароль прямо в коді”.
Що ти вивчиш
У цій лекції ти вивчиш:
- як застосунки підключаються до PostgreSQL;
- що таке підключення до бази даних;
- що означають host, port, назва бази даних, username і password;
- що таке connection string;
- як створити користувача бази даних для застосунку;
- чому не варто використовувати superuser
postgresу застосунку; - як використовувати змінні середовища;
- як працює файл
.env; - типові приклади підключення;
- базові правила безпеки;
- типові помилки підключення;
- різницю між локальною розробкою і production.
До кінця цієї лекції ти зрозумієш міст між 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
Правила:
- кожен автор має унікальний email;
- кожен post належить автору;
- title поста обов’язковий;
- content поста може бути довгим текстом;
- 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 через host, port, database name, username і password;
- PostgreSQL зазвичай використовує port
5432; - connection string об’єднує дані підключення в один URL;
- секрети застосунку мають приходити зі змінних середовища;
- файли
.envкорисні локально, але їх не можна commit з реальними секретами; - застосунки не мають використовувати superuser
postgres; - окремі користувачі бази даних для застосунку безпечніші;
- користувачам потрібні права на tables і sequences;
psqlкорисний для тестування підключення;- Docker змінює те, як працюють host names;
- типові помилки: неправильний пароль, неправильна база, відсутні права і connection refused;
- migrations допомагають керувати структурою бази даних;
- ORM-и корисні, але знання SQL все одно важливе;
- connection pooling допомагає застосункам повторно використовувати підключення до бази даних.
Це важлива лекція.
Тепер ти розумієш, як PostgreSQL підключається до реальних застосунків.
Тут знання бази даних стає backend-силою.
База даних зберігає правду.
Застосунок використовує правду.
Користувач бачить результат.
А десь посередині розробник сподівається, що змінні середовища правильні.
Дуже реально.
Дуже професійно.
Дуже понеділково.
Наступна лекція
У наступній лекції ми поговоримо про backups, restore і базове обслуговування бази даних.
Бо створити базу даних — добре.
Використовувати базу даних — краще.
Але мати можливість відновити дані після проблеми — безцінно.
Backups нудні.
До того дня, коли вони рятують твоє життя.
Тоді вони стають прекрасними.