Proxy Bypass (Self-invocation): Вызов метода с @Transactional, @Async или @Cacheable из другого метода того же класса.
Суть: Spring использует прокси. Внутренний вызов игнорирует прокси, аннотация не срабатывает.
Решение: Выносить метод в другой бин или использовать ApplicationContext (хуже).
Stateful Singleton (Состояние гонки в бинах): Использование мутабельных полей (коллекций, счетчиков) в @Service или @Component.
Суть: Spring-бины — синглтоны. При конкурентных запросах данные перемешаются.
Решение: Хранить состояние в БД/кэше, либо использовать ThreadLocal / потокобезопасные коллекции (если это оправдано).
Transaction Starvation (I/O внутри транзакции): Сетевые вызовы (HTTP/gRPC) или тяжелая работа с файлами внутри @Transactional.
Суть: Пул соединений с БД (HikariCP) блокируется на время ответа внешней системы. При нагрузке пул исчерпается, приложение “ляжет”.
Implicit Transaction Rollback (Откат только по RuntimeException): Выброс Checked Exception (например, IOException) внутри @Transactional.
Суть: По умолчанию Spring не откатывает транзакции при Checked исключениях.
Решение: Использовать @Transactional(rollbackFor = Exception.class).
Базы данных, JPA и Hibernate
N+1 Query Problem: Ленивая загрузка связанных сущностей (@OneToMany) внутри цикла.
Суть: Вместо 1 запроса выполняется 1+N.
Решение: Использовать JOIN FETCH, @EntityGraph или DTO-проекции.
Lombok-ловушки в JPA (@Data, @ToString, @EqualsAndHashCode): Использование этих аннотаций над @Entity.
Суть: Вызов toString() или equals() дергает ленивые связи, вызывая LazyInitializationException или StackOverflowError (при двунаправленных связях).
Misunderstanding Dirty Checking: Ручной вызов save() для уже прикрепленной (attached) к Hibernate-сессии сущности, или ожидание сохранения без @Transactional.
Missing Modification Context: Использование кастомных @Query("UPDATE/DELETE...") без @Modifying.
Open Session In View (OSIV) Anti-pattern: Включенный по умолчанию в Spring Boot OSIV.
Суть: Транзакция БД закрывается, но сессия БД держится открытой до конца рендеринга HTTP-ответа. Ведет к истощению пула коннектов.
Многопоточность и Concurrency
Non-Atomic “Check-then-Act”: Проверка состояния и последующее изменение (например, if (!map.containsKey()) map.put()) без синхронизации.
Суть: Между проверкой и действием другой поток может изменить состояние.
Решение: Использовать putIfAbsent, computeIfAbsent или блокировки.
False Atomicity (Иллюзия атомарности volatile): Использование volatile для операций инкремента (counter++).
Суть:volatile гарантирует только видимость (visibility), но не атомарность. Инкремент — это 3 операции.
Решение:AtomicInteger или synchronized.
Thread-Unsafe Standard Classes: Использование SimpleDateFormat или MessageDigest как статических констант.
Суть: Они не потокобезопасны.
Решение: Использовать DateTimeFormatter (java.time) или ThreadLocal.
Lost Async Exceptions: Запуск задач через ExecutorService.submit() без вызова .get() у Future.
Суть: Исключения внутри потока “проглатываются” и не попадают в лог.
Core Java, Collections и Stream API
Side-Effects in Streams: Мутация внешней коллекции внутри stream().forEach() или map().
Суть: Нарушает функциональную парадигму, при .parallelStream() ведет к потере данных или ConcurrentModificationException.
Решение: Использовать .collect().
Optional Misuse: Вызов .get() без .isPresent(), использование Optional в полях класса или аргументах методов.
Суть:Optional создан только для возвращаемых значений методов, чтобы избежать NPE.
Suboptimal Lookups (O(N^2) Complexity): Использование List.contains() внутри цикла или фильтра стрима.
Суть: Поиск по списку работает за O(N).
Решение: Конвертировать список для поиска в HashSet (O(1)) до начала цикла/стрима.
Unclosed Resources: Работа с потоками ввода-вывода (I/O) или JDBC без try-with-resources.
Floating Point Money (Деньги в double/float): Использование типов с плавающей точкой для финансовых расчетов.
Суть: Стандарт IEEE 754 не может точно представить некоторые дроби (0.1 + 0.2 != 0.3).
Решение: Только BigDecimal (с конструктором от String) или хранение в копейках/центах (long).
Reference vs Value Equality: Сравнение объектов (String, Integer) через == вместо .equals().
Суть: Сравниваются ссылки в памяти. Из-за пула строк и кэша Integer (-128..127) баг может плавать.
5. Архитектура, Логирование и Безопасность
Log and Throw Anti-pattern: Логирование ошибки и немедленный проброс её же выше по стеку.
Суть: Дублирование одного и того же стектрейса на всех слоях приложения.
Решение: Либо логируй и обрабатывай, либо пробрасывай дальше.
Swallowed Exceptions: Пустой блок catch или логирование только e.getMessage() без передачи самого объекта исключения.