SC24EP03 Работа с базами данных - Разработка проектов со Spring

Поділитися
Вставка
  • Опубліковано 7 бер 2024
  • Третий ролик цикла посвящён работе с реляционными СУБД с применением Spring Data JPA. Кроме этого вкратце демонстрируется версионирование баз данных при помощи FlywayDB.
    В цикле роликов "Разработка проектов со Spring" я рассказываю на простых примерах о процессе разработки веб-приложений и REST-сервисов на языке программирования Java с использованием экосистемы Spring. Данный цикл охватывает разработку классических и реактивных проектов, вопросы их сопровождения, такие как документация и мониторинг, адаптацию их к облачной инфраструктуре и процесс их развёртывания в Docker и Kubernetes.
    Репозиторий проекта: github.com/alex-kosarev/sc24/...
    Мои ресурсы:
    - Сайт: alexkosarev.name
    - Канал на UA-cam: / @shurik_codes
    - Канал в Telegram: t.me/+TZCuO38vG3oqu_Jq
    - Группа для обсуждений в Telegram: t.me/+UFAkw187WstX0wqy
    - Паблик в VK: shurik.codes
    - Канал в Дзене: dzen.ru/shurik_codes
    - Канал на Rutube: rutube.ru/channel/24432001/
    - Страница в Boosty: boosty.to/akosarev
    Поддержать проект:
    - Доны в VK: donut/shurik.codes
    - Донаты в Boosty: boosty.to/akosarev/donate
    - Через Tinkoff: www.tinkoff.ru/cf/4PEOiVCZQuS
    #java #spring #data #jpa #hibernate #flyway #sql #postgresql

КОМЕНТАРІ • 70

  • @ratsmasher
    @ratsmasher 3 місяці тому +23

    Один из немногих разработчиков на ютубе, который так подробно и продвинуто обьясняет разработку приложений на спринг и все что с ним связано. У других максимум найдешь создание простых CRUD приложений, а тут на канале обхват тем и фич коллосальный. Очень много полезной инфы узнал из роликов!

  • @Devivl
    @Devivl 3 місяці тому +5

    Потрясающий универсальный подарок на 8 марта - годный контент от сельского джависта :)
    Твоих любимых и дорогих людей с праздником, Саня!
    Добра, любви, тепла и всего самого хорошего!

  • @airat2010
    @airat2010 Місяць тому +2

    Это очень качественный и от настоящего профессионала, контент!

  • @ArtemShishkinV
    @ArtemShishkinV 3 місяці тому +3

    Спасибо за урок!
    Таймкоды, вдруг кому-то полезно будет:
    00:00 - Об основных понятиях урока(JPA, Hibernate, Spring Data JPA, Flyway)
    03:54 - Подключение зависимостей
    04:36 - Описание структуры БД
    07:42 - Маппинг сущности в коде на сущность в БД (@Entity)
    14:08 - Создание @Repository
    19:00 - Настройка подключения к БД
    23:00 - Баг-фикс изменения товара(update в БД)
    26:30 - Вводная информация по созданию пользовательских запросов к БД
    28:00 - Cоздание пользовательского запроса к БД по названию метода в репозитории
    35:45 - Создание пользовательского запроса к БД с использованием JPQL(@Query, @Param)
    38:50 - Создание пользовательского нативного запроса к БД (nativeQuery = true)
    39:50 - Создание пользовательского именованного запроса (@NamedQueries)
    44:00 - Добавление возможности фильтрации списка товаров на UI
    48:25 - Подведение итогов

  • @user-br4gt7xu2j
    @user-br4gt7xu2j 2 місяці тому +3

    Спасибо, Александр! Очень крутой цикл видео! И уровень разработки крутой. Отдельное спасибо за внимание к каждому комментарию, это очень приятно) Вы очень хорошее дело делаете!
    При просмотре не понял пару деталей:
    1) зачем везде this? он вроде бесполезен в нормальном коде, где имена полей никогда не совпадают с именем аргумента
    2) зачем такое именование полей БД? это же боль для стороннего программиста, тестировщика, DBA, аналитика
    3) зачем примитивы в полях и аргументах? Это будущие NPE при взаимодействии слоев, сервисов, десериализации и вдобавок дефолтное значение в отличии от ссылки, несущее кучу неочевидных багов потенциально
    4) зачем возвращать из репозитория Iterable? не лучше ли наследовать более подходящий интерфейс вместо Crud (JpaRepository например)
    5) почему не использовались read only транзакции над методами чтения? будет лишний dirty checking при каждой выборке, а это создание, копирование и сравнение массивов всех полей всех сущностей каждый раз под капотом
    6) операция patch тут разве правильно реализована? получается в реальности put (осуществляется замена всех полей сущности, а патч подразумевает только модификацию тех, которые были заданы), более того такая реализация неконсистентна со структурой сущности (структура изменится, а патч нет - придется руками менять при каждой модификации структуры)
    7) почему обработка ошибок рест клиента через try-catch, ProblemDetail и cast к списку? выглядит как костыль. Тут разве не просится получение результата в виде Either объекта и дальнейшая обработка? использование в коде CRUD app явного cast, instanceof или reflection - плохой звоночек. Да и в целом не понятно почему не использовался HTTP Interfaces, там отличная поддержка для RestClient в новых версиях спринга
    8) почему для Rest service не использовался @RestControllerAdvice?
    9) почему вместо возврата List не возвращается Page/Slice? это и обертка над списком значений с метаданными и сразу готовя пагинация с сортировкой
    10) почему не отключен open-in-view? мы же не дергаем прокси из контроллеров, но зато имеем из-за этого открытую сессию хибера на уровне контроллера, а не там, где она реально нужна. Стандартный антипаттерн вроде

    • @shurik_codes
      @shurik_codes  2 місяці тому +2

      Ох, сколько вопросов)
      1. На мой взгляд упрощает читаемость кода, сразу понимаешь, где обращение к членам класса, а где - к локальным переменным. Но, возможно, это сила привычки
      2. Чтобы по названию можно было определить, какую роль выполняет тот или иной элемент. Снова привычка
      3. Ни разу не сталкивался с какими-либо проблемами из-за использования примитивов, стараюсь использовать именно примитивы там, где это возможно
      4. Iterable используется, потому что возвращается по умолчанию, ну и от него требуется только возможность использования итератора. Не вижу смысла в использовании более специфичного JpaRepository в ситуациях, когда хватает функциональности более общего CrudRepository
      5. Тут да, забыл, банально за всем не уследишь
      6. В том-то и дело, что PUT подразумевает полную замену всех свойств сущности (id, title, details), иными словами замену всей сущности, а в запросе фигурируют только свойства, которые мы можем изменить (title, details). Именно поэтому PATCH, а не PUT. PUT замещает объект, а PATCH - изменяет свойства объекта. Для соблюдения консистентности можно воспользоваться версионированием API, но это я буду рассказывать вообще в отдельном ролике.
      7. try/catch - вполне стандартный подход, ProblemDetail - опять же стандартный способ описания HTTP-ошибки в REST API (да, в черновике IETF, но лучше, чем что-то самописное), а каст нужен, т.к. список ошибок передаётся одним из свойств свободной формы. Да, можно было на стороне REST API сформировать строку ошибки и передать её в details. Использование HTTP-интерфейсов - это уже углубление, которое лучше разобрать в отдельном ролике.
      8. Потому что достаточно и обычного @ControllerAdvice
      9. Опять же углубление, про которое нужно отдельно рассказывать, у меня и так ролики получаются большие, а если раскрывать каждую деталь, то они будут ну очень большими
      10. Банально потому что забыл, т.к. на практике давно MVC-приложений не пишу

    • @user-br4gt7xu2j
      @user-br4gt7xu2j 2 місяці тому

      @@shurik_codes Большое спасибо за такой детальный развернутый ответ!)) Ролики у Вас совсем не большие, имхо, максимально лаконично все уложено, даже чрезмерно где-то, а по такой теме 2-3 часа видео - это норма) тот кто смотрит ролик длиной 1ч, тот с удовольствием посмотрит и трехчасовой и пяти, будьте уверены)) Недаром на UA-cam при фильтре определяющие значения 4 мин и 20 мин, они проводили исследования по этому вопросу и 20 мин являются чертой, выше которой человек смотрит практически любой длины видео, а тот кто не смотрит длинные, тот 20 минут не осиливает в свою очередь чаще всего, самая ленивая группа смотрит менее 4 мин всегда (но это касается не только лени, но и типа видео, разумеется)

  • @user-ux1cn3jx5w
    @user-ux1cn3jx5w 2 місяці тому +1

    Очень понятно и при этом хорошо раскрывается тема. Спасибо!

  • @hurricane-rus
    @hurricane-rus 11 днів тому

    Еще важно отметить, что валидация должна делаться в dto, а в entity приводятся только наборы полей, которые мапятся на поля таблиц БД. Скорее всего для экономии времени в проекте это совмещено, но это плохая практика на реальном проекте, потому что приводит к спагетти-коду.
    Когда идет подключение к БД, в настройках конфигурации должен быть указан профиль, иначе ничего не запустится. Best practice - отдельный ямл без постфиксов, где указывается активный профиль, и ямл под каждое отдельное окружение (это будет работать, потому что специализированные ямлы будут наследовать все данные из дефолтного ямла).

  • @johnconnor3553
    @johnconnor3553 3 місяці тому +1

    Счастья и здоровья тебе,добрый человек!

  • @Wemmer123
    @Wemmer123 3 місяці тому +2

    Спасибо ОГРОМЕННОЕ.

  • @romanovichihin2429
    @romanovichihin2429 26 днів тому

    Комент для продвижения

  • @user-rk3ic3qz3h
    @user-rk3ic3qz3h 2 місяці тому +1

    Отлично. Смотрю дальше.

  • @krutaxe
    @krutaxe 3 місяці тому +2

    Супер! Спасибо) 🎉

  • @vadimkharovyuk7660
    @vadimkharovyuk7660 3 місяці тому +1

    Спасибо за урок . Лайк / подписка 🙌

  • @Boraldan
    @Boraldan 3 місяці тому +1

    Всё по полочкам разложил, спасибо.

  • @user-kt7hy5vk3k
    @user-kt7hy5vk3k 2 місяці тому +1

    Отличный материал!!!

  • @itmaker1821
    @itmaker1821 3 місяці тому +1

    Лайк циклу, лайк ролику, лайк автору =)

  • @user-ib7vx3yc4i
    @user-ib7vx3yc4i 3 місяці тому +1

    крутой ролик получился

  • @denisthestudent
    @denisthestudent Місяць тому +1

    Спасибо!

  • @user-dy3rt8xd4c
    @user-dy3rt8xd4c Місяць тому

    всё прекрасно, одно маленькое замечание не у всех ультимейт версия идеи.

  • @ChinukB12
    @ChinukB12 3 місяці тому +5

    Саша, спасибо за контент
    Подскажи, когда планируешь и планируешь ли снимать создание рест приложений с использованием webflux?

    • @shurik_codes
      @shurik_codes  3 місяці тому +2

      В 7 ролике цикла будет

  • @explo9087
    @explo9087 3 місяці тому +1

    Спасибо за очень информативные видео. Может сделаете видео как правильно загружать, хранить и получать файлы с сервера, например картинки через контролеры, тоесть чтоб Product был еще и с картинкой )

  • @kazbowski
    @kazbowski 3 місяці тому +2

    Привет! Спасибо за твои видосы :) Хочу предложить тему для ролика: OTP (one time password) в spring security. По ней достаточно мало материала, а тот что есть - сделан очень коряво. Я сейчас сам начал пытаться реализовать данную тему, и понял, что это прям очень сложно выглядит (приходится переопределять usernamepasswordauthenticationfilter и делать прочие шаманства, что реализовать безопасный ввод кода). Очень бы хотелось увидеть твою реализацию по данной теме. Надеюсь - заинтересует, спасибо!

    • @shurik_codes
      @shurik_codes  3 місяці тому

      Постараюсь такой ролик записать

  • @eapashkov
    @eapashkov 3 місяці тому +2

    Александр, напоминай пожалуйста, что не стоит писать select * from, тебя же новички смотрят)

  • @Hocorend
    @Hocorend Місяць тому

    Спасибо за видео.
    А я думал, что без реализации репозитория в классе, нужно @Repository ставить над интерфейсов, оказалось оно там и не нужно.
    Этот урок оказался коротким, но даже тут узнал что-то новое и крайне полезное, но без заранее подготовленных знаний по работе с БД у новичков будет темный лес)) Но иначе бы пришлось делать урок на пару часов, например, нет ни слова про отношения OneToMany и т.д.

    • @user-fl4yw1cr7d
      @user-fl4yw1cr7d 16 годин тому

      Если я правильно понял о чем речь, то если не ставить аннотацию то не будет в логах специфичные ошибки показывать для бд. А так можно хоть @Component поставить

  • @user-007-1
    @user-007-1 3 місяці тому +2

    Чётко
    Планируется ли ролик по интеграционному тестированию этого приложения?
    По юнит тестам много инфы, а вот хороший пример настойки тестконтейнеров и тестирования бд/брокеров сообщений найти не удалось

    • @shurik_codes
      @shurik_codes  3 місяці тому +1

      В 5 ролике будет

  • @a1K04ek0v
    @a1K04ek0v 2 місяці тому +1

    Александр, спасибо вам за эти замечательные обучающие ролики, все лаконично и на современном стэке! Разрешите задать вопрос, в чем смысл в классах обращаться к инжектируемым сущностям через this, без него ведь то же все будет корректно работать? Вероятно, это просто ваш стиль программирования направленный на поддержание кода в более структурированном и понятном виде))

    • @shurik_codes
      @shurik_codes  2 місяці тому

      Да, это стиль программирования, сразу видно, где обращение к локальным переменным, а где - к свойствам класса

  • @user-yt3wm5on6m
    @user-yt3wm5on6m 3 місяці тому +1

    как вариант еще можно фильтрацию реализовать через findByTitleContainingIgnoreCase(String filter);
    не нужно будет делать проверку на null и blank

    • @shurik_codes
      @shurik_codes  3 місяці тому +1

      Можно и так, я привычен к failfast-стилю

  • @itskovdi
    @itskovdi 2 місяці тому

    17:40 замена List на Iterrable. Можно обойтись без этого и оставить List, если экстендить JpaRepository. JpaRepository экстендится от ListCrudRepository, в котором возвращаемый тип для findAll() это List.

    • @shurik_codes
      @shurik_codes  2 місяці тому

      Можно, но можно оставить и Iterable, т.к. острой необходимости в List в данном примере нет

  • @markostr
    @markostr 3 місяці тому +1

    Все прекрасно у Вас получается! Спасибо ! Очень доходчиво. Но будет ли Join в запросах хотя бы один-ко многим из двух таблиц? И как сериализовать чтобы подучился Json с вложеными блоками в таком случае? И вообще как работает сериализация при запрсах nbgf JOIN итп. Оочень нужно...

    • @shurik_codes
      @shurik_codes  3 місяці тому

      В рамках этого цикла роликов - нет, отдельно надо подумать

  • @temaMalina
    @temaMalina 3 місяці тому +1

    Александр, здравствуйте, огромное спасибо за ролики! А вы не планируете в других роликах, вне цикла, рассмотрение фреймворка Camel? И еще вопрос, а вы использовали restclient, а feignclient в своей работе используете?

    • @shurik_codes
      @shurik_codes  3 місяці тому

      OpenFeign не использую, Camel, скорее всего, будет

  • @akalavan5395
    @akalavan5395 2 місяці тому

    Хотел уточнить, какой вариант запроса лучше использовать на практике или в какой ситуации лучше использовать тот или иной метод создания запроса?

    • @shurik_codes
      @shurik_codes  2 місяці тому

      Использование названий методов - для самых простых вопросов, EntityManager - для самых сложных. В целом никто не запрещает для всех случаев использовать EntityManager. Тут характеристика лучше-хуже не совсем уместна)

  • @Denys.Stoianov
    @Denys.Stoianov 3 місяці тому

    пропустил момент почему используется не паблик схема в преимущества использование не по дефолту и в чем преимущества использования префиксов "t_table _name" и с колонками тоже, это сделано намеренно в целях наглядности, наверное

    • @shurik_codes
      @shurik_codes  3 місяці тому

      Про схему: 5:25, префиксы для наглядности, да

  • @AlexPlanetEarth
    @AlexPlanetEarth 3 місяці тому

    Интересно как реализован save при завешении транзакции, ведь как то где то должен отслеживаться список измененных объектов?
    Получается есть какой то менеджер объектов которых сохраняет ссылку на объект/егопрокси пока не произойдет завершение транзакции?
    Интересно как это в хибере и не только реализуется под капотом.

    • @SlevySoddik
      @SlevySoddik 3 місяці тому +1

      Persistence Context

    • @user-br4gt7xu2j
      @user-br4gt7xu2j 2 місяці тому +2

      Cущесвует несколько уровней кэширования в Hibernate:
      - на уровне сессии(по умолчанию активно)
      - на уровне фабрики сессий(по умолчанию не активно)
      Кэширование на уровне сессии представляет из себя поле в объекте Session, являющееся объектом PersistenceContext, содержащее, строго говоря, набор мап и метаданных с информацией об активных entity.
      Основная из этих мап - поле HashMap entitiesByKey, где K - id сущности(объект EntityKey, содержащий id сущности, хэш и т.н. EntityPersister(специфичный преобразователь ORM, закрепленный за текущим типом entity)), а V - сама сущность.
      Т.о. при попытке получить сущность Hibernate сперва получает ее из этой мапы, а если в ней нет, то получает из DB, после чего добавляет в мапу, чтобы при следующем поиске не идти снова в DB.
      В другой мапе также инициализируется массив всех полей persistent объекта (добавленного в кэш), а при завершении транзакции происходит сравнение значений из этого массива с текущими значениями и если они не совпадают, то сессия считается "грязной"(были изменения объекта в ее ходе) и происходит дополнительный апдейт в БД. Этот механизм (dirty-checking'а, а не самого кэша) можно отключить, если использовать транзакцию с флагом read-only, тогда все апдейты нужно делать явно.

    • @AlexPlanetEarth
      @AlexPlanetEarth 2 місяці тому

      @@user-br4gt7xu2j СпасиБо за развернутый ответ!

  • @dariyershov8152
    @dariyershov8152 2 місяці тому

    Как называется тема на intellij idea? Понравился визуал значков и сочетание цветов

  • @viewer_evgeniy
    @viewer_evgeniy 3 місяці тому

    Здравствуйте, а для создания таблицы if not exists уже не нужно указывать?

    • @kazbowski
      @kazbowski 3 місяці тому

      Это не обязательные атрибуты

    • @shurik_codes
      @shurik_codes  3 місяці тому

      Можно указывать, для схемы я указываю, т.к. FlywayDB сама создаёт схему ЕМНИП, и я не хочу конфликта при выполнении скрипта

  • @alexv1549
    @alexv1549 18 днів тому

    А у меня упорно не стартует ваш проект. WARN на flyway и на отсутствие коннекта к БД, раз я JPA и Postgre в POM указал

    • @shurik_codes
      @shurik_codes  18 днів тому

      А параметры подключения к БД?

    • @alexv1549
      @alexv1549 18 днів тому

      @@shurik_codes если имеется ввиду доп настройки в yaml/property или compose то таковых нет, postgre в Docker запустился нормально. я просто запустил ваш проект с git. Docker только вчера поставил, до этого в глаза его не видел

  • @azsaliance-bw4ui
    @azsaliance-bw4ui 3 місяці тому +2

    Чтобы запрос был более красивым поможет настройка
    spring.jpa.properties.hibernate.format_sql=true

  • @yasha64000
    @yasha64000 2 місяці тому

    без зависимости flyway-database-postgresql кидал Unsupported Database

    • @shurik_codes
      @shurik_codes  2 місяці тому

      Код к ролику: github.com/alex-kosarev/sc24/tree/SC24EP03-spring-data-jpa всё работает без этой зависимости

  • @eapashkov
    @eapashkov 3 місяці тому

    Ты на мак пересел?

  • @087773016049
    @087773016049 3 місяці тому +1

    Саша, спасибо, полезный контент.