Ответ
В последнем проекте в качестве основной реляционной базы данных использовалась PostgreSQL. Для взаимодействия с ней применялся стек Spring Data JPA поверх Hibernate.
Пример сущности и репозитория:
// Сущность (Entity)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
// Другие поля, связи (@OneToMany, @ManyToOne)
// Getters and Setters
}
// Репозиторий (Spring Data JPA)
public interface UserRepository extends JpaRepository<User, Long> {
// Декларативный метод для поиска
Optional<User> findByEmail(String email);
// Пример запроса с @Query (JPQL)
@Query("SELECT u FROM User u WHERE u.createdAt > :date")
List<User> findUsersCreatedAfter(@Param("date") LocalDateTime date);
}
Дополнительные инструменты и практики:
- Миграции схемы: Использовали Flyway для версионирования и применения изменений структуры БД (DDL).
- Сложные запросы: Для динамических или сложных запросов применяли QueryDSL или нативные SQL-запросы (
@Query(nativeQuery = true)). - Кэширование: Для повышения производительности часто запрашиваемых данных подключали Redis в качестве кэша второго уровня (L2 cache) или для хранения сессий.
Ответ 18+ 🔞
А, ну это классика, блядь! В прошлом проекте мы, как нормальные люди, взяли PostgreSQL — она ж как швейцарские часы, надёжная сука. А чтобы с ней не общаться на голом SQL, как дикари, натянули сверху Spring Data JPA с Hibernate. Это ж как переводчик с человеческого на язык таблиц, блядь!
Смотри, как это выглядит, если по-простому:
// Это типа паспорт для записи в таблице "users"
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // Главный номер, сам растёт, красота
@Column(nullable = false, unique = true)
private String email; // Почта, и чтоб одна на весь мир, ёпта!
// Тут ещё куча полей могла быть, связи всякие...
// Getters and Setters
}
// А это — волшебная говорящая коробка для работы с юзерами
public interface UserRepository extends JpaRepository<User, Long> {
// Спросишь у неё "найди по мылу" — она сама запрос сообразит, ядрёна вошь!
Optional<User> findByEmail(String email);
// А если надо похитрее, так и напишешь запрос прямо тут
@Query("SELECT u FROM User u WHERE u.createdAt > :date")
List<User> findUsersCreatedAfter(@Param("date") LocalDateTime date);
}
И всё, казалось бы, ебушки-воробушки! Ан нет, жизнь-то сложнее.
Что ещё прикручивали, чтобы не облажаться:
-
Миграции (Flyway): А то как без них? Представь, у тебя десять программистов начинают в схему БД тыкать пальцами, как слепые котята. Flyway — это такой строгий архитектор, который говорит: «Все изменения — по версиям, по порядку, и ни хуя самовольничать!». Чтоб на проде не вышло, что у тебя таблица есть, а у коллеги — уже нет, пиздец.
-
Сложные запросы: Spring Data JPA — она хороша, пока запросы простые. А как только нужно «найди тех, у кого имя как Иван, но заказов больше пяти, а ещё они из Москвы, но только если не заблокированы» — тут уже Hibernate начинает тупить, как мартышлюшка. Поэтому для такой динамической хуйни брали QueryDSL — он запросы из кусочков лепит. А для совсем уж запредельной логики — нативные SQL-запросы (
@Query(nativeQuery = true)). Да, приходилось пачкать руки, зато быстро, блядь. -
Кэширование (Redis): Ну а куда без этого? База — она хоть и быстрая, но не железная. Когда каждый второй запрос летит за одними и теми же данными (типа «список городов» или «настройки пользователя»), гонять это в PostgreSQL — это просто издевательство. Redis ставили как быстрый буфер. Туда складывали часто нужную хуйню, и приложение сразу оттуда хватало, не дергая основную базу. Иногда его же для хранения сессий юзали — чтобы кластер не тупил, где какой пользователь залогинен.
Вот так и жили: JPA для рутины, а когда припрет — достаём тяжёлую артиллерию в виде нативных запросов и Redis. Главное — понимать, где какой инструмент ебёт эффективнее.