Repository: доступ до бази без SQL
Репозиторій — це шар між нашим кодом і базою даних. Ми викликаємо методи Java, а Spring Data JPA сам генерує SQL.
UserRepository extends JpaRepository (12.1.png)
Рис. 5 Інтерфейс UserRepository, який наслідує JpaRepository<User, Long>. Це одна стрічка — а можливостей додає дуже багато.

1) Що таке репозиторій (Repository) простими словами

Repository — це компонент, який “вміє” працювати з таблицею в базі даних: зберігати, читати, оновлювати і видаляти записи.

Уяви це як “пульт керування таблицею”:

  • натиснув save() → запис зберігся в БД
  • натиснув findAll() → отримав всі записи
  • натиснув findById() → отримав конкретний рядок
  • натиснув deleteById() → видалив запис

Головна ідея: у коді ми не пишемо SQL “руками”. Ми працюємо методами Java, а Spring Data JPA перетворює це на SQL.

2) Що ми зробили конкретно тут

Ми створили інтерфейс:

public interface UserRepository extends JpaRepository<User, Long> {}

Тобто ми сказали Spring:

  • цей репозиторій працює з сутністю User;
  • тип ID у цієї сутності — Long;
  • і ми хочемо отримати всі CRUD-методи, які вже є у JpaRepository.

3) Що таке Spring Data JPA і чому це “магія” працює

Spring Data JPA — це надбудова над JPA/Hibernate, яка:

  • автоматично створює реалізацію репозиторію “під капотом”;
  • генерує SQL запити на основі методів;
  • дає стандартний набір CRUD-операцій для кожної сутності.

Ти пишеш інтерфейс, а Spring під час запуску створює клас-реалізацію (через проксі). Тому в нас немає класу UserRepositoryImpl — але все працює.

4) Розбір JpaRepository<User, Long> по частинах

User — сутність, тобто таблиця users.

Це означає: репозиторій буде робити SQL саме для таблиці users.

Long — тип первинного ключа (id).

Має збігатися з типом поля id у сутності User: private Long id; або private long id;

Якщо ти випадково поставиш Integer замість Long — будуть дивні помилки, бо Spring не зможе правильно працювати з id.

5) Які методи ми отримали автоматично (без жодного коду)

Після extends JpaRepository у нас вже є десятки методів. Найважливіші:

  • save(entity) — вставка/оновлення (INSERT або UPDATE)
  • findAll() — отримати всі записи
  • findById(id) — знайти по id (повертає Optional)
  • existsById(id) — перевірити, чи існує запис
  • deleteById(id) — видалити по id
  • count() — кількість записів у таблиці

Ключовий момент: Це не “наші” методи — вони вже реалізовані в Spring Data. Ми просто підключили їх для нашої сутності.

6) Як Spring вирішує: INSERT чи UPDATE у save()?

Spring Data JPA дивиться на поле id:

  • якщо id = null (або 0 для примітиву) → це новий об’єкт → робить INSERT;
  • якщо id вже є → вважає, що запис існує → робить UPDATE.

Тому правильна генерація id через @GeneratedValue критично важлива.

7) Питання студентів: “А де анотація @Repository?”

У багатьох прикладах ви побачите @Repository, але тут ми її не писали. Чому все одно працює?

  • Spring Data JPA автоматично реєструє інтерфейси-репозиторії як Spring Beans;
  • тобто він сам “помічає” їх як репозиторії під час сканування.

Висновок: у Spring Data JPA анотація @Repository часто не потрібна явно. Але концептуально репозиторій — це саме Repository-компонент.

8) Як додавати власні методи: “магія назв” (Derived Queries)

Фішка Spring Data: ти можеш написати метод в інтерфейсі, і Spring згенерує SQL за його назвою.

Наприклад, якщо в User є поле email, ми можемо додати:

Optional<User> findByEmail(String email);

І Spring сам зробить приблизно такий SQL:

SELECT * FROM users WHERE email = ?;

Тобто ми не пишемо запит. Ми описуємо “що хочемо” в назві методу.

Правило: назва методу має відповідати полю сутності. Якщо поле називається email, то метод має містити ByEmail.

9) Repository vs Service: де має бути логіка?

Репозиторій — це “доступ до даних”. Бізнес-логіка має бути в Service.

  • Repository: save, find, delete, прості запити.
  • Service: перевірки, правила, обробка помилок, транзакції, об’єднання кількох репозиторіїв.

Якщо логіку пхати в Repository — код стає важко підтримувати. У нормальному проєкті репозиторій максимально “тупий”, сервіс — “розумний”.

10) Типові помилки (щоб одразу попередити)

  • Забули залежність Spring Data JPA → JpaRepository не працює.
  • Не збігається тип ID (User має Long, а в репозиторії Integer) → помилки типів.
  • Метод findByEmail написали, а поля email у сутності немає → Spring впаде при старті.
  • Repository викликають з Controller напряму → потім важко додати логіку/перевірки.

Підсумок: репозиторій — це “двері” в базу даних. Тепер ми можемо читати і зберігати User без SQL. Наступний крок — створити Service, щоб додати логіку і зробити код правильно структурованим.