Тру-Джава
137 subscribers
31 photos
79 links
блог начинающего Java-программиста

Чат: https://t.me/trujavachat
Download Telegram
Всем привет!

На днях изучала официальный сайт Kafka и там было хорошее видео, объясняющее, что такое кафка. Оно на английском, поэтому я решила выложить здесь перевод некоторых моментов из видео:

Десятилетиями мы хранили информацию, как некие 'данные' в базе данных. Это могут быть какие-то сущности, такие как пользователь, или что-то другое. Сейчас, многие стали думать о том, что хранить только данные недостаточно. Нужно хранить события (логи) - что-то случилось тогда-то в этом-то месте, например, такой-то пользователь обновил свой пост.

Кафка - это система, которая помогает управлять этими событиями. Эти события кафка называет топиками (topic с английского означает тема).

Топик - это упорядоченная коллекция событий, которые надежно хранятся. Надежно - имеется в виду, что хранение происходит на нескольких дисках / серверах, так чтобы эти события не потерялись.

Топики могут быть маленькие, могут быть огромные, храниться могут несколько секунд или бесрочно.

Кафка мотивирует разработчиков думать о событиях сначала и 'данных' потом.

Как можно использовать кафка топики? Микросервисы могут общаться друг с другом через такие топики. Один микросервис может получить сообщение из кафка топика, сделать с ним что-то и отправить информацию в другой кафка топик, который хранит события для другого приложения.

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

Это базовое представление о том, что такое кафка и что она из себя представляет.

Определение с официального сайта:
Kafka - это распределенная потоковая платформа, предлагающая три основные возможности:
1. чтение сообщений из очереди и запись их в очередь;
2 надежное хранение сообщений;
3 обработку потоков данных по мере их появления.
👍8🔥2
Всем привет!

Расскажу свои последние новости. После тестового задания по соцсети, меня пригласили к ним на собеседование, правда назначили мне его на 4 сентября. Сказали, что будет разговор о Spring и Spring Security.

Активно пошла разбираться в тонкостях, читая книжки и статьи по Security, думаю к концу недели написать пост о каком-нибудь теоретическом вопросе на эту тему.

Вчера ещё в одной организации начался java интенсив, на который я попала в группу из 22 человек. Было первое занятие, позиционировалось, как лекция, но на деле было знакомство. Так что потренировалась делать краткую самопрезентацию.

Потом лектор стал каждому задавать по два вопроса по Java Core и многие на них споткнулись. Вопросы в принципе были не сложные, но человека без подготовки могут застать врасплох.

Поэтому напишу некоторые вопросы здесь:
1. Отличие Comparable от Comparator.
2. Что такое блоки инициализации. Какие бывают и в каком порядке запускаются, если есть наследники.
3. Что такое дженерики (мне достался вопрос)
4. К какому типу данных относятся массивы, можно ли хранить примитивные типы данных в коллекциях.
5. Разница между final, finally и finalize.

Есть репозиторий с ответами на эти и похожие вопросы, здесь.
🔥2👏2
С Днем Знаний! 😁

У нас сегодня открылось задание на диплом. Будем реализовывать огромный, судя по всему, проект с несколькими микросервисами. Нужно выбрать дополнительную функциональность для него из нескольких на выбор. Я пока не определилась, но склоняюсь к функциональности «рейтинги». Там будет проект на тему событий, которые можно было бы оценивать, или, наоборот, хейтить :) В зависимости от рейтинга потом сортировать при выдаче.

Пока закрыт был доступ к диплому делала свой проект-блог. Настроила Spring Security, JWT, сделала, чтобы подсчет просмотров постов велся с помощью Kafka. Пока у меня есть два топика, один больше для логов, в качестве практики. А второй вот для подсчетов просмотров постов.

На интенсиве вчера был созвон с обсуждением Git, SOLID, задавались нам опять вопросы, только на этот раз не только по Java Core, но и по алгоритмам. На следующий созвон планируется подробная проверка наших знаний, как устроены коллекции.

Вчера отвлекалась от мыслей о сегодняшней линейке как могла: посмотрела видео Евгения Борисова о Spring (его видео - просто огонь, всем советую, кто еще не смотрел), читала Spring Security в действии, потом захотелось переключиться от Spring и стала читать MongoDB for Jobseekers (тоже интересная книжка).
👍6🔥1
Всем привет!

Сегодня у меня было первое техническое собеседование. Пишу поделиться впечатлениями.

Все вопросы касались Spring, за редким исключением, всего длилось 1.5 часа.

Много говорили о бинах, сервлетах, подробно говорили о самом Hibernate, этапах жизни сущности, proxy.

Узнала много нового, например, что можно использовать environment переменные в пропертиз файле. Выписала себе много новых аннотаций.

Из смешного - забыла о чем один из последних моих проектов, он учебный, с двумя микросервисами. Буквально пару-тройку недель назад его сдала, а сегодня наотрез забыла о чем он 😅

С одной стороны, можно понять, я тут много чем другим занималась это время, но всё равно вышло немного неловко))

Кстати, вчера ещё небольшое достижение получилось, пошла решать задачи на экзамен для стажировки в Тинькофф (уже третья попытка) и получилось побить собственный рекорд решенных задач - в первый раз, весной, решила всего одну задачу, в июне, уже решила две с половиной (половина не отрабатывала на всех примерах входных данных), а в этот раз, вчера, решила уже 4 (с половиной).

Думаю всё дело в том, что тема задач была не какая-то там абстрактная, про каких-нибудь Вовочек-маминых хакеров, а более реалистичная. Можно даже сказать брутальная и жизненная. Во всех задачах герой был Ковбой Джо, не сопереживать которому было просто невозможно 😁
🔥7👍1
Всем привет!

Пришел ответ с собеседования - не прошла. Вердикт: "есть пробелы в Spring Security, Spring JPA/Hibernate. Рекомендация: Изучить моменты Spring Security (Authentication, SecurityContext, Principal, GrantedAuthority). Так же подтянуть Hibernate."

Сразу стали вспоминаться вопросы именно по этим двум темам, на которые не ответила:

1. В чём разница между методом save у Hibernate и методом save у JpaRepository?

Вкратце, метод JpaRepository вызывает метод EntityManager.persist() - если сущность сохраняется впервые - либо метод EntityManager.merge() - если сущность обновляется. Метод save у Hibernate специфично ORM фреймворку и не работает со спецификацией JPA (вызывается метод Session.save, статья).

2. В чём разница между аутентификацией и авторизацией в Spring Security?

Аутентификация - процедура проверки подлинности (сравниваются введенный логин и пароль с сохраненным в базе данных)

Авторизация - предоставление прав на определенные действия (прав у админа, например, больше). (Статья)

3. Где хранится Authentication, как мы понимаем, что пользователь именно тот, за кого себя выдает?

Ответ: В SecurityContext. Две статьи на эту тему: раз и два.

Вот так разнятся требования на джунов, где-то спрашивают, зачем переопределять equals&hashCode, а где-то и такие вопросы задаются🤔
👍9
Всем привет!

Сегодня хочу порекомендовать курс со Stepik, называется «Middle Java Developer для МТС Банк». Он бесплатный, проводился для своих и, видимо, остался для остальных, кому интересно. Я вышла на него случайно, еще летом, но занималась по нему не активно. Даже периодически про него совсем забывая.

Вчера, когда сделала пару эндпоинтов для диплома, решила, что можно в честь выходного и отдохнуть от него и вспомнила про этот курс. Пошла читать, там у меня было открыто на Stream API, на моменте, где рассказывалось про метод GroupingBy у стримов. Он работает, как GROUP BY в SQL. В дипломе я его применила до этого, но больше случайно, погуглив. Но после статьи об этом методе с разными способами применения, очень понравились его возможности.

После стримов была ссылка на вебинар и мне очень понравился спикер. Он очень интересно рассказывал, давал интересные задачки на разные неоднозначные ситуации в многопоточности, потом приводил примеры из жизни, где такие ситуации происходят сплошь и рядом, если не учитывать некоторые моменты.

После этого оставшуюся часть дня смотрела другие вебинары с этого курса, благо на степике можно пропускать до любого интересного урока и заниматься, как удобно. Посмотрела вебинары этого спикера на тему Spring Security и интеграционного тестирования. Очень понравилось. В конце курса еще задание есть огромное, большой проект. Думаю сделаю его после диплома.

Диплом медленно идет, потому что заранее не знаешь как, что должно работать. Есть спецификация по эндпоинтам. Делаешь метод, тестируешь по их тестам Postman, оказывается, что в тестах вызывается другой, еще не написанный эндпоинт. Или по спецификации думаешь, что должен быть такой-то ответ, потом методом проб и ошибок в тестах постман, понимаешь, какой же ответ все-таки ожидается на самом деле.

Интереснее, когда есть идея сделать что-то и ты сидишь и думаешь как это сделать. Пишешь сама тесты, знаешь, что хочешь увидеть и видишь, когда что-то идет не так. Тут, наоборот, у тебя есть некоторые детали и ты из них собираешь общую картину, угадывая, как это должно взаимодействовать. Угадывая, потому что все тесты постман написаны со скрытыми деталями, типа {{request body}}, {{uid}}. То есть с одной стороны, test driven development, а с другой, guess driven development. Но делать нечего, надо его писать))
🔥8👍21
С профессиональным праздником Днем программиста всех причастных и сочувствующих! 🥳🥳🥳
🎉13
Всем привет!

Сегодняшний пост посвящается Spring Security.

Что такое Spring Security?

Его описывают, как мощный и хорошо настраиваемый фреймворк для контроля аутентификации и авторизации.

Spring Security - это фреймворк, который перехватывает запросы, аутентифицирует пользователей, применяет правила контроля доступа и защищает ваше приложение от угроз безопасности. Его главная цель убедиться, что ваше приложение защищенно, путем предоставления богатого набора инструментов для аутентификации и авторизации пользователей.

Как работает Spring Security?

Spring Security перехватывает HTTP запросы и пропускает через серию фильтров.

Сначала проверяет аутентифицирован ли пользователь (смотрит вошел ли пользователь, через свой логин/пароль), если нет, то перенаправляет его на страницу входа (для ввода логин/пароля).

Когда пользователь ввел данные, Spring Security сравнивает эти данные с теми, которые хранятся у нас в базе данных.

После аутентификации, Spring Security проверяет какие права и к каким ресурсам можно пустить пользователя (согласно нашей настройки).

Вот так может выглядеть метод, в котором мы прописываем фильтры для проверки пользовательских запросов (для версий Spring 3.0.9 и ниже):

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.authorizeHttpRequests((authz) -> {
try {
authz
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/users/**").hasRole("USER")
.anyRequest().permitAll()
.and()
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
return http.build();
}

Подробнее о том, что такое csrf и cors, а также, как изменилась настройка фильтров в более поздних версиях Spring, в следующих постах.

Здесь пока можно увидеть, что для пути /admin будут допущены пользователи с ролью Admin, а к пути /users только пользователи с ролью User, также в этой цепочке фильтров можно увидеть, что к другим эндпоинтам разрешены любые запросы (anyRequest().permitAll()).

Определения взяты из Spring Security in Action by Laurentiu Spilca. Продолжение следует 🤓
👍7🎄1
Привет!

Есть любители Ломбок? Делала на днях ревью (на интенсиве) и узнала новую для себя аннотацию- @Cleanup - заменяет try with resources. Очень украшает код.

Например, метод без аннотации:

public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}

А теперь метод с аннотацией:

public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}

Мне понравилась идея 😊
👍8🔥4
Всем привет!

Сегодня будет небольшой апдейт. На прошлой неделе немного выпала из жизни - писала диплом. Вчера отправила на проверку 2 этап. Когда зачтут, останется только добавить свою фичу небольшую и готово.

Думаю буду делать рейтинг событий с лайками, дизлайками и общей 5 звездочной оценкой. По заданию нужно будет самой написать Postman тесты - это будет новый опыт для меня. До этого тестировала там сама свои проекты вручную, проверяя разные запросы на разные эндпоинты, потом уже писала юнит и интеграционные тесты.

Стала потихоньку возвращаться к книжкам, курсу на степике. Сейчас у меня одновременно начато очень много книг, поэтому решила читать по очереди, чтобы не разрываться. Первая в очереди Spring Security in Action, очень стала интересна тема безопасности, столько в ней есть нюансов, что хочется в этом разбираться.

Потом думаю буду дочитывать Kafka в действии и Spring Паттерны. Сегодня попалось в каком-то чате, что есть Kafka Security (streams security) - захотелось посмотреть, почитать.

Но всё сразу читать не получается, буду стараться сохранять очередность))
🔥7👍2
Всем привет!

На днях в Практикуме был вебинар с нашим наставником группы. Его спросили про JPA и Null параметры. Он предложил вариант сделать дерево условий, если этот пришедший параметр null, то не передавать его в метод репозитория.

Самое интересное, что в нашем случае приходило 7 null параметров в одном из тестов. Кажется, что это 7 условий. Но что если приходит 5 параметров null, а остальные не null? Это дополнительное условие, потому что нет колонок со значением null в нашей таблице событий. Когда я делала этот эндпоинт, я прикинула, что это (минимум) 21 вариация. 14 if-else условий проверки на null на каждый параметр, плюс варианты, когда первые два null, а остальные не null, первый и третий null, а остальные не null. В этом духе.

Естественно, этот момент предусмотрен в Spring Data JPA. Подробнее можно посмотреть в этой статье. Я выпишу пример с коротким объяснением из этой статьи:

@Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name) and (:email is null or c.email = :email)") 
List<Customer> findCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email);

В этом случае, если параметр name будет null, условие будет верно всегда и не повлияет на выборку WHERE. По поводу конструкции @Param("name"), в моем случае работало и без нее.

Может кому пригодится, если вдруг кто не знал про это.
👍11🔥1
Всем привет!

C 19 сентября из каждого (утюга) java канала сообщалось про выход новой версии java 21. А мой канал что? Не утюг? 😅 На самом деле, расписывать новшества я не буду, потому что они уже много где были хорошо описаны, например, я читала, кроме документации, эту статью.

Диплом мне сегодня зачли, поэтому самое время начать вплотную знакомиться с новой версией джава. Меня привлекло, что в новой версии в switch кейсах, наконец, можно будет добавлять условие, с помощью ключевого слова when:

case Integer i when i > 0 -> String.format("positive int %d", i); 


Я такую возможность захотела в первый день, когда впервые экспериментировала со switch конструкцией в прошлом году. Единственное, смущает, что новый паттерн-матчинг имеет ограничения, например, что кейсы должны быть исчерпывающими. Но в этом плане я еще не до конца разобралась, сегодня только пришла идея поэкспериментировать с нововведениями.

Еще из новостей, во вторник у меня было собеседование на стажировку в нашем городе. Результаты будут только на следующей неделе. Вопросы были очень легкими, в стиле, что такое класс Object, какие у него есть методы? Чем отличается ArrayList от LinkedList? Как, вкратце, устроена HashMap? Чем отличается аннотация @Controller от @RestController? Зачем ставить аннотацию @Repository? Такого рода вопросы.
🔥5😁2
Самое главное, ради чего писался пост, забыла написать 😁:

Презентацию новой версии я частично смотрела онлайн. Приободрило, как начинающего разработчика, когда у троих опытных разработчиков Oracle не получилось запустить видео со звуком. Минут 5 они возились и говорили разные приободряющие слова, в стиле: «Мы разработчики, нам свойственно ошибаться. Но мы не сдаемся, пока не победим»💪
😁8
Всем привет!

Хочу рассказать о том, что поняла только на днях (к своему стыду). Первый звонок, что что-то здесь не так, прозвучал, когда писала пост про null параметры. Сначала я написала, что это JPA Hibernate, потом перечитала начало статьи и увидела, что это Spring Data JPA, исправила.

Потом посмотрела видео про паттерны в Spring, Евгения Борисова, услышала ещё раз про Spring Data, второй звонок.

Вчера начала читать книгу про Hibernate (идея с чтением книг последовательно, окончательно провалилась) и паззл в голове сложился.

Есть 3 отдельных понятия: JPA, Native Hibernate, Spring Data JPA.

Как я думала до этого? Что есть спецификация JPA со стандартами, есть ORM фреймворк для выполнения этих стандартов, один из таких Hibernate. И есть где-то Spring Data, которая что-то где-то делает, где и что я не знала.

Так вот оказывается Spring Data JPA делала много чего у меня прямо под носом: делала реализацию моих запросных методов (findByNameAndEmail), бин-реализацию для моих интерфейсов-репозиториев, которые наследовались от JpaRepository, и избавляла меня от написания повторяющегося кода.

Сейчас я точно вспоминаю, что нам про это рассказывалось в теории в Практикуме, но в тот момент в голове по полкам не разложилось. Лучше поздно, чем никогда 😅
👍5🔥1
Всем привет!

Есть ли жизнь после Практикума?🤪 Когда долго ждешь окончания чего-нибудь, и это на самом деле заканчивается, становится немного пусто, появляются мысли: "И что теперь?"

В пятницу я неофициально закончила курсы "Java-разработчика" в Яндекс.Практикум (официальное окончание будет 14 октября). Получается надо редактировать свой вступительный пост здесь.🤭 Но глобально, что же делать дальше?

Когда была система спринтов и я раньше времени что-то заканчивала, четко знала, что будет дальше в программе (в общих чертах), знала что всегда будет какой-то проект, задачки/тесты. А тут появилась неуверенность в "завтрашней программе".

Поэтому пошла искать себе такую программу. Посмотрела разные пути развития (roadmap), требования из нескольких вакансий, и наметила себе посмотреть Elasticsearch, GraphQL, MongoDB и, возможно, Kubernetes.

Нашла классный туториал по первому здесь, по второму здесь, а по MongoDB недавно скачала классную книжку (MongoDb for Jobseekers).

Также ещё нашла интересный репозиторий на гитхаб с полезными ссылками, awesome java, и там нашла интересную вещь, как game development engines для разработки игр на java. Я давно сыну обещала сделать игру для него в стиле его любимой игры, думаю попробовать jMonkeyEngine.

Посчитала, из относительно крупных учебных проектов у меня накопилось 4 учебных, и 4 своих (2 из них появились благодаря интересным тестовым заданиям). Был у меня репозиторий сфоркнутый с тестовыми заданиями, думала взять какую-нибудь идею в разработку, но в основном проекты там мелкие, в стиле "простой калькулятор", игра, где смысл показать, что ты умеешь в наследование.

Поэтому отфоркнула этот репозиторий, добавила в свой блог-проект создание постов с ролью авторов (method security), и, отложив его пока, решила разнообразить свое портфолио ещё и игрой на java. В блог можно, конечно, добавить рейтинг, комментарии, но это всё выглядит в принципе не очень сложно, несколько раз реализовывала похожий и такой же функционал и совсем недавно, поэтому решила пока переключиться и попробовать сделать что-то совсем другое (дополнительно к туториалам выше).👨‍💻
👍81
Всем привет!

Я прошла на стажировку! Точнее, я прошла на две стажировки, но одна из них была в Астон, где очень жесткие условия. Поэтому туда я отказалась идти. На прошлой неделе у меня было собеседование на другую стажировку с возможностью дальнейшего трудоустройства в их компанию. Вчера пришел результат, что я прошла, начало будет 2 октября. Поделюсь впечатлениями, как начнется.

Вчера еще вспомнила про курс для миддлов со степика. Еще раз захотелось его порекомендовать, он бесплатный. Там многие вещи пересекаются с курса Я.Практикума для джунов, но чем мне нравится — деталями по темам. Курс, видимо, создан был Семеном Кирековым, потому что его вебинары на курсе самые крутые и полезные и ссылки на «почитать подробнее на тему» ведут на его блог. Правда, пишет он там на английском, поэтому подойдет не всем. Но на степике теоретические статьи на русском.

На моем собеседовании по Spring и Hibernate, собеседующий спросил меня, как правильно создавать базы для приложения. Я наивно ответила, что нужно создавать файл schema.sql. Он сказал: «Нет, есть способ лучше». Но какой не сказал. Тут на курсе, нашла ответ — нужно делать, так называемые, миграции. В курсе рассказывается про инструмент миграции Liquibase, приведены примеры как, объяснено почему.

Еще интересная вещь, которую я сегодня там прочитала — объяснение, что это за такое предупреждение, которое у нас всегда выходило в учебных проектах, помню даже ответ наставника, мол, не заморачивайтесь. Вот так выглядит это предупреждение:

2022-04-13 23:01:34.863  WARN 109326 --- [main] JpaBaseConfiguration$JpaWebConfiguration : 
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering.
Explicitly configure spring.jpa.open-in-view to disable this warning

Оказывается, это антипаттерн с названием Open Session in View. Он сделан для обхода исключения LazyInitializationException, которое бросает Hibernate, когда ему необходимо инициализировать связанную сущность, для которой указана «ленивая» загрузка, но при этом отсутствует контекст сессии Hibernate (попросту говоря, когда мы запросили сущность из базы без дополнительных полей — сущностей хранящихся в других таблицах, а потом обратились к этим полям, по типу event.getCategories() или book.getGenres()).

«Суть данного антипаттерна в том, что сессия Hibernate открывается и закрывается не в сервисном слое, а в слое "выше" - на уровне представления (view layer), к примеру в контроллере. Контроллер вызывает сервисный слой, который выполняет различные действия с данными и возвращает управление контроллеру. А поскольку сессия всё ещё открыта, слой представления может инициализировать объекты, для которых указана "ленивая" загрузка. Однако если сервисный слой выполнит commit, то транзакция завершится. Из-за этого Hibernate будет выполнять все SQL-запросы, инициированные на слое представления, в режиме auto-commit, то есть каждый такой SQL-запрос будет выполняться в отдельной транзакции, что приведёт к повышению нагрузки на БД, т.к. в конце каждой транзакции БД должна сделать запись в журнале транзакций на диске, что является ресурсозатратной операцией.

Помимо повышения нагрузки на БД у Open Session In View есть и другой недостаток. Поскольку операции выполняются не в одной транзакции, а в двух и более, можно получить неконсистентное состояние данных. Spring Boot по умолчанию использует Open Session in View.» Чтобы это отключить, нужно установить false параметру spring.jpa.open-in-view в application.properties.
6🔥6👏4👍1
Всем привет!

Хочу рассказать об интересной вещи, которую узнала вчера-позавчера. Начну немного издалека. Не очень давно, на последнем моем занятии на интенсиве, мы обсуждали Hibernate и кто-то задал вопрос: "почему считается, что 'жадная' выборка данных (fetch eager) не решает проблему n + 1? Казалось бы, не для этого ли ее придумали?"

Вкратце напомню, что это за проблема "n + 1". Она часто возникает, когда мы обращаемся к какой-то сущности, например, книге, которая имеет связь с другой сущностью, например, жанром. У одной книги может быть несколько жанров, и у одного жанра может быть несколько книг. Такая связь называется многие-ко-многим и по умолчанию в Hibernate для нее выполняется ленивая загрузка (fetch lazy).

Таким образом, если мы запросим список книг из репозитория, Hibernate сгенерирует один запрос. Если мы захотим пройтись по жанрам книг в цикле, в каких-нибудь статистических, фильтрующих или других целях, из-за того, что загрузка жанров ленивая, то есть данные запрашиваются только тогда, когда они нужны, для каждой книги Hibernate сделает дополнительный запрос в базу данных, чтобы получить жанры этой книги.


List<Book> books = bookRepository.findAll();
for (Book book : books) {
List<Genre> genres = book.getGenres();
// делаем что-то с жанрами
}


Что делает Hibernate, если указать параметр fetch EAGER? Он генерирует дополнительные запросы сразу, до обращения к жанрам, поэтому EAGER не решает проблемы n + 1!

Это я узнала буквально пару дней назад и это меня очень поразило🤓

P. S. Это не решение проблемы n + 1, это объяснение почему FETCH EAGER не решает эту проблему. О решениях будет отдельный пост позже 🤗
👍101
Всем привет!

Вчера у меня началась классная стажировка. Было первое занятие, познакомились, наметили план работы. Впечатления отличные.

Будем разрабатывать интересный проект. Он будет включать в себя 6 микросервисов (плюс минус). В проекте будет использоваться Liquibase, Spring Security, RabbitMQ (возможно аналог), будут push-уведомления, обращения к внешним сервисам. В общем, очень близко к настоящему взрослому проекту. Будут допущены некоторые упрощения в учебных целях, но для меня это будет самый большой проект, пока что.

Liquibase, кстати, начала тестировать в выходные. Решила сделать проект из курса для миддлов (до этого планировала переключиться на разработку игры на jMonkeyEngine и что-то пока ничего из этого не вышло, даже не знаю с чего там начать).

С Liquibase не сразу получилось, я ещё включила у Hibernate настройку для ddl-auto на validate, по совету с курса, чтобы была проверка на соответствие сущностей и реальной базы. Учитывая, что первый раз делала базы через Liquibase, проект у меня очень долго не заводился, но было интересно. В конце концов получилось, думаю в свободное время буду продолжать его делать, пока не началась активная разработка нового проекта.
👍8👏2
Всем привет!

Смотрела вчера лекцию по API безопасности. Там говорилось о последних стандартах PCI DSS 4.0*, которые должны применить у себя компании до 1 квартала 2024 года.

Вкратце расскажу несколько моментов, что было сказано в видео:

1. Количество API растёт, в прогнозах ещё больше будет рост, в силу удобства подхода.

2. Часто делают проверки безопасности на уровне клиента (браузера, например) - делают невидимыми различные кнопки пользователям без доступа к таким ресурсам, к примеру. В этом случае злоумышленники, если найдут верный эндпоинт, могут напрямую получить доступ к данным (отправив прямой запрос на эндпоинт), если нет дополнительных проверок для API.

3. Одной из хороших практик была названа практика Security Gateway, специальный сервис, ответственность которого аутентифицировать и авторизовывать пользователей.

Сразу же загорелась попробовать реализовать такой сервис в последнем проекте с миддл курса. Если следовать их ТЗ, там тоже есть упрощения, которые я хочу усложнить для себя и попробовать сделать ближе к тому, как надо. Поэтому этот проект превращается в мой пет, потому что я меняю для себя требования, как должно работать. Тем более, что начала писать на хайпе на Java 21 (может я увидела хайп там, где его нет, конечно 😅) и на последней стабильной версии Spring Boot. Там настройка Spring Security немного отличается.

Осталось дело за малым, найти как это правильно сделать 😅, нашла пока статью с 7 вариантами, буду что-нибудь из этого пробовать)

P. S. Кстати, не говорила вроде бы, что этот проект - клон учебного сайта Coursera (на минималках).

*Стандарт PCI DSS — это международный стандарт безопасности, созданный специально для защиты данных платежных карт.
👍81
Всем привет!

Вернемся к проблеме “n + 1”, о которой я недавно делала пост. Там я рассказала об одном соблазнительном, но неправильном решении. Кстати сказать, один раз я применила его летом в одном из ТЗ Я.Практикума. Тогда мне ревьюер интересно ответила, что раньше бы она сказала на fetch eager, что это 100% нельзя использовать, но сейчас у них тимлид заставляет всех использовать fetch eager на проекте. То есть можно представить, какая нагрузка идет на базу данных, когда ВСЕ запросы идут, как n + 1, правда?

Какие есть правильные решения?

1. Использовать JOIN FETCH в аннотации @Query:

    @Query(value = "" +
"SELECT c FROM Course c " +
" JOIN FETCH c.lessons")
List<Course> findAll();

2. Использовать аннотацию @EntityGraph над методом в репозитории:

@EntityGraph(attributePaths = {"lessons"})
List<Course> findAllUsingEntityGraph();

В аргументе attributePaths аннотации @EntityGraph указывается тот объект, который необходимо инициализировать сразу, несмотря на установленный у него ленивый тип загрузки.

Хочу сказать интересную вещь про join fetch.

Возможно это для всех сразу стало очевидным, когда они первый раз прочитали про join fetch, но я об этом узнала только вчера. Оказывается join fetch — это inner join fetch, то есть если нам нужно соединение left join, то нужно указывать left join fetch. Я этого не знала, на дипломе в таких случаях использовала запросы на нативном SQL в @Query. Об @EntityGraph я также не знала еще неделю-две назад, ее еще не применяла на практике. Но в этой статье можно посмотреть примеры, как ее нужно применять.
👍3🔥2