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

Третий ролик цикла посвящён работе с реляционными СУБД с применением Spring Data JPA. Кроме этого вкратце демонстрируется версионирование баз данных при помощи FlywayDB.
В цикле роликов "Разработка проектов со Spring" я рассказываю на простых примерах о процессе разработки веб-приложений и REST-сервисов на языке программирования Java с использованием экосистемы Spring. Данный цикл охватывает разработку классических и реактивных проектов, вопросы их сопровождения, такие как документация и мониторинг, адаптацию их к облачной инфраструктуре и процесс их развёртывания в Docker и Kubernetes.
Репозиторий проекта: github.com/alex-kosarev/sc24/...
Мои ресурсы:
- Сайт: alexkosarev.name
- Канал на KZread: / @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

Пікірлер: 64

  • @ratsmasher
    @ratsmasher2 ай бұрын

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

  • @airat2010
    @airat201016 күн бұрын

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

  • @romanovichihin2429
    @romanovichihin242934 минут бұрын

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

  • @denisthestudent
    @denisthestudent17 күн бұрын

    Спасибо!

  • @Devivl
    @Devivl2 ай бұрын

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

  • @ArtemShishkinV
    @ArtemShishkinV2 ай бұрын

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

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

  • @user-br4gt7xu2j
    @user-br4gt7xu2jАй бұрын

    Спасибо, Александр! Очень крутой цикл видео! И уровень разработки крутой. Отдельное спасибо за внимание к каждому комментарию, это очень приятно) Вы очень хорошее дело делаете! При просмотре не понял пару деталей: 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

    Ай бұрын

    Ох, сколько вопросов) 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

    Ай бұрын

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

  • @johnconnor3553
    @johnconnor35532 ай бұрын

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

  • @user-kt7hy5vk3k
    @user-kt7hy5vk3kАй бұрын

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

  • @user-rk3ic3qz3h
    @user-rk3ic3qz3h2 ай бұрын

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

  • @Wemmer123
    @Wemmer1232 ай бұрын

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

  • @Boraldan
    @Boraldan2 ай бұрын

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

  • @azsaliance-bw4ui
    @azsaliance-bw4ui2 ай бұрын

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

  • @Hocorend
    @Hocorend22 күн бұрын

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

  • @krutaxe
    @krutaxe2 ай бұрын

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

  • @vadimkharovyuk7660
    @vadimkharovyuk76602 ай бұрын

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

  • @ChinukB12
    @ChinukB122 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @itmaker1821
    @itmaker18212 ай бұрын

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

  • @eapashkov
    @eapashkov2 ай бұрын

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

  • @user-ib7vx3yc4i
    @user-ib7vx3yc4i2 ай бұрын

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

  • @user-dy3rt8xd4c
    @user-dy3rt8xd4c27 күн бұрын

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

  • @shurik_codes

    @shurik_codes

    26 күн бұрын

    это да

  • @a1K04ek0v
    @a1K04ek0vАй бұрын

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

  • @shurik_codes

    @shurik_codes

    Ай бұрын

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

  • @user-007-1
    @user-007-12 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @kazbo4431
    @kazbo44312 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @explo9087
    @explo90872 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Подумаю

  • @itskovdi
    @itskovdiАй бұрын

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

  • @shurik_codes

    @shurik_codes

    Ай бұрын

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

  • @markostr
    @markostr2 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @temaMalina
    @temaMalina2 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @user-yt3wm5on6m
    @user-yt3wm5on6m2 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @akalavan5395
    @akalavan5395Ай бұрын

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

  • @shurik_codes

    @shurik_codes

    Ай бұрын

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

  • @dariyershov8152
    @dariyershov8152Ай бұрын

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

  • @shurik_codes

    @shurik_codes

    Ай бұрын

    New UI

  • @AlexPlanetEarth
    @AlexPlanetEarth2 ай бұрын

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

  • @SlevySoddik

    @SlevySoddik

    2 ай бұрын

    Persistence Context

  • @user-br4gt7xu2j

    @user-br4gt7xu2j

    Ай бұрын

    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

    Ай бұрын

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

  • @Denys.Stoianov
    @Denys.Stoianov2 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @viewer_evgeniy
    @viewer_evgeniy2 ай бұрын

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

  • @kazbo4431

    @kazbo4431

    2 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @yasha64000
    @yasha640002 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @eapashkov
    @eapashkov2 ай бұрын

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

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Нет

  • @087773016049
    @0877730160492 ай бұрын

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

Келесі