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

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

КОМЕНТАРІ • 84

  • @ratsmasher
    @ratsmasher 6 місяців тому +29

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

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

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

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

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

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

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

  • @odtour
    @odtour 9 днів тому

    28:20 Где настроить эти подсказки?

    • @shurik_codes
      @shurik_codes  8 днів тому +1

      Оно уже сконфигурировано в IDEA Ultimate

  • @tedbear6330
    @tedbear6330 Місяць тому +3

    Отличные уроки! Для всех кто пользуется Spring Boot 3.3.2: по мимо тех зависимостей, которые добавил Александр, нужно также добавлять flyway-database-postgresql для работы с postgresql из flyway. Версию можно неуказывать Dependecy manager сам разберется

  • @ровойт
    @ровойт 2 місяці тому +2

    сделайте какой-то новый проект более интересный и больший - когда будут новые уроки

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

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

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

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

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

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

  • @hurricane-rus
    @hurricane-rus 3 місяці тому +1

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

  • @ArtemShishkinV
    @ArtemShishkinV 6 місяців тому +4

    Спасибо за урок!
    Таймкоды, вдруг кому-то полезно будет:
    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 - Подведение итогов

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

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

  • @AlexSmile-y2x
    @AlexSmile-y2x 5 місяців тому +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  5 місяців тому +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-приложений не пишу

    • @AlexSmile-y2x
      @AlexSmile-y2x 5 місяців тому

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

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

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

    • @shurik_codes
      @shurik_codes  6 місяців тому

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

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

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

    • @shurik_codes
      @shurik_codes  6 місяців тому

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

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

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

  • @odtour
    @odtour 9 днів тому

    47:57 Почему знак вопроса - это процент? И зачем вообще их туда добавлять, т.е. почему без них не работает?

    • @shurik_codes
      @shurik_codes  8 днів тому +1

      Знаки процента, банальная оговорка. Добавлять нужно для нестрогого сравнения по тексту

  • @yasha64000
    @yasha64000 5 місяців тому +1

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

    • @shurik_codes
      @shurik_codes  5 місяців тому

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

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

      спасибо большое! думал щас на 2 часа застряну с этой проблемой

    • @КатеринаКатерина-э9э
      @КатеринаКатерина-э9э Місяць тому

      Спас ваш комментарий! Спасибо)
      А не подскажите почему без нее не работало?

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

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

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

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

  • @Евгений-ы4м3ж
    @Евгений-ы4м3ж 5 місяців тому +1

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

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

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

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

    Огонь. Огромное спасибо

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

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

    • @shurik_codes
      @shurik_codes  6 місяців тому

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

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

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

    • @shurik_codes
      @shurik_codes  5 місяців тому

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

  • @AlLu-u7v
    @AlLu-u7v 6 місяців тому +1

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

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

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

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

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

  • @Константин-ы9к
    @Константин-ы9к 6 місяців тому +1

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

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

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

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

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

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

    спасибо)!

  • @ДмитрийТищенко-е9ъ
    @ДмитрийТищенко-е9ъ 5 місяців тому +1

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

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

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

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

    Спасибо!

  • @goodvideobro
    @goodvideobro 6 місяців тому +1

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

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

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

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

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

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

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

    • @t0tom427
      @t0tom427 11 днів тому

      Наверное уже не надо, но у меня была такая проблема и решил ее добавлением flyway-database-postgresql зависимости в maven, может кому поможет

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

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

  • @itskovdi
    @itskovdi 5 місяців тому

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

    • @shurik_codes
      @shurik_codes  5 місяців тому

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

  • @dariyershov8152
    @dariyershov8152 5 місяців тому

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

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

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

    • @shurik_codes
      @shurik_codes  6 місяців тому

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

  • @Hocorend
    @Hocorend 4 місяці тому

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

    • @СемёнСердюков-д7р
      @СемёнСердюков-д7р 3 місяці тому

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

  • @akalavan5395
    @akalavan5395 5 місяців тому

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

    • @shurik_codes
      @shurik_codes  5 місяців тому

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

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

    а каким образом определяется url для базы данных? (jdbc:postgresql://localhost:5432/catalogue). Просто определенный шаблон, который начинается с "jdbc:postgresql", а хост можно указать любой? И "/catalogue" здесь указывается название схемы?

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

      jdbc:://:/, подробнее: docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html

  • @ИгорьПавлов-ч1ф
    @ИгорьПавлов-ч1ф 4 місяці тому

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

  • @viewer_evgeniy
    @viewer_evgeniy 6 місяців тому

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

    • @kazbowski
      @kazbowski 6 місяців тому

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

    • @shurik_codes
      @shurik_codes  6 місяців тому

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

  • @eapashkov
    @eapashkov 6 місяців тому

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

  • @AlexPlanetEarth
    @AlexPlanetEarth 6 місяців тому

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

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

      Persistence Context

    • @AlexSmile-y2x
      @AlexSmile-y2x 5 місяців тому +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 5 місяців тому

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

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

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