Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Нормализация — это процесс приведения структуры базы данных к оптимальному виду для устранения избыточности данных и обеспечения их целостности. Процесс состоит из последовательных этапов, соответствующих нормальным формам (НФ).
Основные нормальные формы (НФ):
Данные делятся на атомарные (неделимые) значения.
Пример: В одной ячейке таблицы не может быть списка телефонов, вместо этого создается отдельная строка для каждого телефона.
Требует выполнения 1НФ и исключения зависимости от части составного первичного ключа. Это устраняет проблему дублирования данных.
Пример: Если таблица использует составной ключ (например, "Курс" и "Студент"), информация, относящаяся только к "Курсу", выносится в отдельную таблицу.
Выполняется 2НФ и устраняются транзитивные зависимости — неключевые атрибуты должны зависеть только от ключа.
Пример: Если в таблице есть "ID сотрудника", "Отдел" и "Название отдела", то "Название отдела" переносится в отдельную таблицу "Отделы".
Редко используемые нормальные формы:
- Нормальная форма Бойса-Кодда (BCNF): Уточнённая версия 3НФ, где каждое определяющее множество является суперключом. Используется для устранения более сложных аномалий.
- Четвёртая нормальная форма (4НФ): Устраняет многозначные зависимости, которые появляются при использовании нескольких связей между одними и теми же атрибутами.
- Пятая нормальная форма (5НФ): Делает базу данных устойчивой к разделению данных, устраняя зависимости соединений.
Эти формы применяются в сложных сценариях, например, при проектировании корпоративных систем с огромным количеством взаимосвязей. Для большинства приложений 3НФ оказывается достаточной.
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤6🔥3
Spring Security 7
Hi Spring fans! In this installment, we look at username/passwords, one-time tokens, passkeys, multi-factor authentication, and OAuth, and a bunch of other nice features in Spring Security 7!
🌐 🗣 СМОТРЕТЬ VKVIDEO
🎞 🗣 СМОТРЕТЬ YOUTUBE
Подписывайся на наш канал в Max🟪
Hi Spring fans! In this installment, we look at username/passwords, one-time tokens, passkeys, multi-factor authentication, and OAuth, and a bunch of other nice features in Spring Security 7!
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥5❤2
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤3
Spring Framework и Spring Boot с нуля! 🚀 (12 часов)
Это видео поможет вам с нуля освоить Spring Framework и Spring Boot. В нем вы:
Познакомитесь с основными инструментами.
Разберетесь в принципах работы Spring Framework изнутри.
Научитесь создавать полноценное приложение, используя всё, о чем говорится в видео.
Если вы никогда не работали со Spring Framework или переходите с другого языка программирования на Java, это видео станет отличным стартом для изучения этого фреймворка и начала работы над собственными проектами!
🌐 🗣 СМОТРЕТЬ VKVIDEO
📝 🗣 СМОТРЕТЬ DZEN
Подписывайся на наш канал в Max🟪
Это видео поможет вам с нуля освоить Spring Framework и Spring Boot. В нем вы:
Познакомитесь с основными инструментами.
Разберетесь в принципах работы Spring Framework изнутри.
Научитесь создавать полноценное приложение, используя всё, о чем говорится в видео.
Если вы никогда не работали со Spring Framework или переходите с другого языка программирования на Java, это видео станет отличным стартом для изучения этого фреймворка и начала работы над собственными проектами!
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥4👍2
ConcurrentHashMap – это высокопроизводительная реализация Map, специально разработанная для многопоточной среды. Она гарантирует безопасность данных при одновременном доступе и минимизирует использование блокировок.
- Compare-And-Swap используется для операций записи, что позволяет избегать блокировок для большинства операций. Операции с разными бакетами могут выполняться параллельно, поскольку локальная блокировка применяется только к отдельному узлу или бакету.
- Fine-Grained Locking минимизирует область блокировок. Например, если требуется масштабирование (resize) или обработка коллизий, потоки могут продолжать работу с другими бакетами, даже если один из них временно заблокирован.
- synchronized применяется только для случаев, когда CAS не справляется (например, при реорганизации данных или сложных операциях). Это помогает поддерживать баланс между безопасностью и производительностью.
📚 Основные методы:
Легковесная операция, не требует блокировок. Ключ хэшируется, затем вычисляется индекс сегмента. Если в сегменте есть соответствующий узел, он возвращается.
- Сначала используется CAS для вставки нового элемента.
- Если CAS не срабатывает (например, при наличии коллизии), включается локальная блокировка на соответствующей корзине.
Более сложные операции, которые комбинируют вычисления с модификацией. Используются короткие локи для минимизации блокировки других потоков.
- ConcurrentHashMap не допускает хранения null для ключей и значений. Это связано с невозможностью различать отсутствие значения и реальное хранение null.
- Итерации по карте предоставляют "слабо согласованные" данные, что означает, что изменения, происходящие параллельно, могут быть частично видны.
Документация
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤5👍4
💡 Spring Boot Tip
Когда вы строите REST API в Spring Boot, часто используют префикс
Но добавлять
Гораздо проще задать единый префикс через конфигурацию:
Так вы автоматически добавляете /api ко всем контроллерам из нужного пакета, а код контроллеров остаётся чистым.
Подписывайся на наш канал в Max🟪
Когда вы строите REST API в Spring Boot, часто используют префикс
/api для всех контроллеров. Но добавлять
@RequestMapping("/api") в каждый контроллер — неудобно и захламляет код.Гораздо проще задать единый префикс через конфигурацию:
@Configuration
class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api",
aClass -> aClass.getPackage().getName()
.startsWith("com.sivalabs.bookstore"));
}
}
Так вы автоматически добавляете /api ко всем контроллерам из нужного пакета, а код контроллеров остаётся чистым.
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤5🔥4😁1
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤3👍2
Media is too big
VIEW IN TELEGRAM
Знакомство с Resilience4j. CircuitBreaker
В этом видео знакомимся с компонентом библиотеки Resilience4j - CircuitBreaker
📺 🗣 СМОТРЕТЬ RUTUBE
🌐 🗣 СМОТРЕТЬ VKVIDEO
📝 🗣 СМОТРЕТЬ DZEN
Подписывайся на наш канал в Max🟪
В этом видео знакомимся с компонентом библиотеки Resilience4j - CircuitBreaker
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2🔥2
Совет 👩💻 Spring Retry
Spring Retry предлагает возможность автоматического повторного выполнения неудачной операции. 🔥
🖥 Github
Подписывайся на наш канал в Max🟪
Spring Retry предлагает возможность автоматического повторного выполнения неудачной операции. 🔥
@Configuration
@EnableRetry
public class Application {
}
@Service
class Service {
@Retryable(retryFor = RemoteAccessException.class)
public void service() {
// ... do something
}
@Recover
public void recover(RemoteAccessException e) {
// ... panic
}
}
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍5❤1
Builder — это порождающий паттерн, который позволяет пошагово создавать сложные объекты. Вместо того чтобы создавать объект одним большим конструктором с множеством параметров, Builder организует процесс создания по частям, обеспечивая гибкость и читаемость кода.
Использование:
Преимущества:
Недостатки:
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍4🔥2
Совет по Java/JPA: в JPA можно использовать native queries не только для SELECT, но и для INSERT, UPDATE и DELETE.
Важно: такие операции идут в обход EntityManager/PersistenceContext, поэтому изменения не попадают в контекст и не синхронизируются с сущностями автоматически.
На примере Spring Data JPA:
- @Modifying позволяет выполнять модифицирующие запросы
- nativeQuery = true — включает нативный SQL
- clearAutomatically / flushAutomatically управляют очисткой и синхронизацией контекста транзакции
Нативные INSERT/UPDATE/DELETE удобны, когда нужна высокая производительность, сложный SQL или массовая вставка данных.
Подписывайся на наш канал в Max🟪
Важно: такие операции идут в обход EntityManager/PersistenceContext, поэтому изменения не попадают в контекст и не синхронизируются с сущностями автоматически.
На примере Spring Data JPA:
- @Modifying позволяет выполнять модифицирующие запросы
- nativeQuery = true — включает нативный SQL
- clearAutomatically / flushAutomatically управляют очисткой и синхронизацией контекста транзакции
Нативные INSERT/UPDATE/DELETE удобны, когда нужна высокая производительность, сложный SQL или массовая вставка данных.
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥6❤3
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥3
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3🔥3
🔒 Pessimistic vs Optimistic Locking
🟡 Pessimistic Locking
- Запись недоступна для других потоков до тех пор, пока текущий поток не закончит работу с ней.
- Даже чтение данных другими потоками невозможно, пока лок не снят.
- Пример: EntityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE) в JPA.
- Минусы: снижает производительность при высоком уровне конкурентного доступа.
- Когда применять: при критической необходимости точности данных.
🟡 Optimistic Locking
- Не блокирует данные при чтении, но проверяет версию записи при сохранении.
- Пример: аннотация @Version в JPA (колонка для хранения версии).
- Если версия изменена другим потоком, выбрасывается OptimisticLockException.
- Минусы: требует обработки конфликтов.
- Когда применять: при большом количестве чтений и низкой вероятности конфликтов.
❓ Какой подход вы чаще используете в своих проектах?
Подписывайся на наш канал в Max🟪
- Запись недоступна для других потоков до тех пор, пока текущий поток не закончит работу с ней.
- Даже чтение данных другими потоками невозможно, пока лок не снят.
- Пример: EntityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE) в JPA.
- Минусы: снижает производительность при высоком уровне конкурентного доступа.
- Когда применять: при критической необходимости точности данных.
- Не блокирует данные при чтении, но проверяет версию записи при сохранении.
- Пример: аннотация @Version в JPA (колонка для хранения версии).
- Если версия изменена другим потоком, выбрасывается OptimisticLockException.
- Минусы: требует обработки конфликтов.
- Когда применять: при большом количестве чтений и низкой вероятности конфликтов.
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤6🔥5❤🔥1
Фасад — это структурный паттерн, который предоставляет унифицированный интерфейс для работы с набором сложных подсистем. Он скрывает сложность системы и упрощает взаимодействие с ней, предоставляя более простой и понятный API для клиента.
Использование:
Преимущества:
Недостатки:
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥5❤🔥4❤1
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍9🔥5
А вы задумывались, что скрывается под капотом Arrays.sort()? Быстрая сортировка? Пузырёк? Или, может, что-то ещё?
На самом деле, Arrays.sort() – это больше, чем просто сортировка. Этот метод использует адаптивные алгоритмы и оптимизации, которые подстраиваются под тип данных и размер массива. А главное – в его реализации предусмотрена защита от худших случаев, таких как неудачное распределение данных, чтобы всегда обеспечивать стабильную производительность.
Для массивов примитивных типов (int, double и т.д.) используется Dual-Pivot Quicksort. Он выбирает два опорных элемента, которые делят массив на три части: элементы меньше первого опорного, между опорными и больше второго, с последующей рекурсивной сортировкой каждой части.
🔍 Как это выглядит:
if (arr[left] > arr[right]) {
swap(arr, left, right);
}
int pivot1 = arr[left];
int pivot2 = arr[right];
int i = left + 1, lt = left + 1, gt = right - 1;
while (i <= gt) {
if (arr[i] < pivot1) {
swap(arr, i++, lt++); // Элементы меньше первого опорного
} else if (arr[i] > pivot2) {
swap(arr, i, gt--); // Элементы больше второго опорного
} else {
i++; // Элементы между опорными
}
}
swap(arr, left, --lt);
swap(arr, right, ++gt);- Использование двух опорных элементов снижает глубину рекурсии.
- Разбиение на три части позволяет сбалансировать массив быстрее, чем в классическом Quicksort.
- Работает in-place, избегая лишних выделений.
- Даже на отсортированных или случайных данных Dual-Pivot Quicksort показывает стабильную производительность.
Если вы сортируете объекты (String, Integer и т.д.), то под капотом работает Timsort – гибридный алгоритм, который сочетает Merge Sort и Insertion Sort. Он адаптивно обрабатывает массивы, находя уже отсортированные последовательности (run'ы) и минимизируя количество операций для их слияния.
🔍 Как это выглядит:
int runLen = 32; // Минимальная длина run
for (int i = 0; i < array.length; i += runLen) {
insertionSort(array, i, Math.min((i + runLen - 1), array.length - 1));
}
while (stackSize > 1) {
if (runLen[stackSize - 2] <= runLen[stackSize - 1]) {
mergeRun(stackSize - 2, stackSize - 1); // Слияние соседних run'ов
}
}
- Timsort автоматически находит уже отсортированные подмассивы, уменьшая объём работы.
- Работает с заранее выделенными буферами для быстрого слияния подмассивов.
- Сохраняет порядок равных элементов, что важно для многих задач.
- Производительность близка к O(n) на частично отсортированных данных.
Для массивов с небольшим количеством элементов (до 32) используется Insertion Sort (сортировка вставками). Он работает, проходя по массиву и вставляя каждый элемент на своё место в уже отсортированной части, сдвигая элементы, которые больше текущего, вправо. Этот алгоритм применяется, так как на малых объёмах данных он оказывается быстрее более сложных методов благодаря низким накладным расходам и простоте реализации.
🔍 Как это выглядит:
for (int i = left + 1; i <= right; i++) {
int key = array[i];
int j = i - 1;
while (j >= left && array[j] > key) {
array[j + 1] = array[j];
j--;
}
array[j + 1] = key;
}- Алгоритм не требует дополнительной памяти и выполняется in-place.
- Сложность O(n^2) на больших данных компенсируется эффективностью на длине до 32 элементов.
- Использует уже загруженные данные в кэше процессора, что ускоряет доступ к памяти.
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤8🔥4
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤6🔥6😁4
Проверяемые исключения (Checked Exceptions)
Непроверяемые исключения (Unchecked Exceptions)
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍3🔥1
Подписывайся на наш канал в Max
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🔥2👍1