SQL Window Functions.pdf
129.5 KB
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2😁1
⚡️ Как ускорить тесты в 6 раз
Знакомая история: пушишь, идёшь за кофе, возвращаешься, а CI ещё думает.
Автор разобрал реальный backend-монолит и сократил время прогона тестов в 6 раз. Только диагностика и последовательные шаги.
Что внутри:
— Почему timeoutInSeconds = 10 — это мина замедленного действия
— HikariCP exhaustion при параллельных suite'ах — и как считать нужный pool size
— Shared Testcontainer через lazy val в object: потокобезопасно и без костылей
— Кастомный Reporter, который не даёт тестам деградировать снова
Стек Scala/SBT, но всё применимо к любому JVM-проекту.
👉 Подробнее в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
Знакомая история: пушишь, идёшь за кофе, возвращаешься, а CI ещё думает.
Автор разобрал реальный backend-монолит и сократил время прогона тестов в 6 раз. Только диагностика и последовательные шаги.
Что внутри:
— Почему timeoutInSeconds = 10 — это мина замедленного действия
— HikariCP exhaustion при параллельных suite'ах — и как считать нужный pool size
— Shared Testcontainer через lazy val в object: потокобезопасно и без костылей
— Кастомный Reporter, который не даёт тестам деградировать снова
Стек Scala/SBT, но всё применимо к любому JVM-проекту.
👉 Подробнее в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤2👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁28💯7👍2🔥1🌚1
Java Developer — удалёнка
Java-разработчик — от 220 000 ₽ — удалёнка
Senior Java Engineer (JavaSE, algorithms, optimization) — от 5 000 $ — удалёнка
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2❤1👍1
🔧 Spring Cache + Redis: настройка которая не сломается в production
🔹 Решение
▪️ Конфигурация RedisCacheManager
▪️ Использование с явным ключом
▪️ Защита от cache stampede через @CachePut + Lock
Сериализация через
⚠️ Никогда не кешируйте Hibernate entity напрямую. Создавайте DTO, сериализуйте его.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
@Cacheable выглядит просто. До первого падения сериализации в production или гонки при cache stampede.🔹 Решение
▪️ Конфигурация RedisCacheManager
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration defaults = RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues(); // null не кешируем
Map<String, RedisCacheConfiguration> configs = Map.of(
"users", defaults.entryTtl(Duration.ofHours(1)),
"products", defaults.entryTtl(Duration.ofMinutes(5)),
"sessions", defaults.entryTtl(Duration.ofDays(1))
);
return RedisCacheManager.builder(factory)
.cacheDefaults(defaults)
.withInitialCacheConfigurations(configs)
.build();
}
}
▪️ Использование с явным ключом
@Cacheable(value = "users", key = "#userId", unless = "#result == null")
public User findById(Long userId) { ... }
@CacheEvict(value = "users", key = "#user.id")
public User update(User user) { ... }
// Evict всего кеша при массовых операциях
@CacheEvict(value = "users", allEntries = true)
public void importUsers(List<User> users) { ... }
▪️ Защита от cache stampede через @CachePut + Lock
@Service
public class ProductService {
private final Map<Long, Object> locks = new ConcurrentHashMap<>();
public Product getProduct(Long id) {
Product cached = cacheManager.getCache("products").get(id, Product.class);
if (cached != null) return cached;
// только один поток пересчитывает, остальные ждут
Object lock = locks.computeIfAbsent(id, k -> new Object());
synchronized (lock) {
// double-check после захвата лока
cached = cacheManager.getCache("products").get(id, Product.class);
if (cached != null) return cached;
Product product = repository.findById(id).orElseThrow();
cacheManager.getCache("products").put(id, product);
return product;
}
}
}
Сериализация через
GenericJackson2JsonRedisSerializer сохраняет информацию о типе в JSON (@class поле). Это позволяет десериализовать полиморфные структуры, но требует чтобы все классы в графе объекта были сериализуемы Jackson'ом. Проблема обычно вылезает при кешировании Hibernate entity с lazy коллекциями — они не сериализуются и роняют приложение.══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1🔥1😁1
Forwarded from Библиотека задач по Java | тесты, код, задания
Что произойдёт, если JwtFilter не вызовет chain.doFilter() внутри своей логики?
Anonymous Quiz
21%
Следующий фильтр в цепочке не выполнится, запрос попадёт сразу в контроллер
11%
Spring Security автоматически продолжит цепочку
32%
Запрос не дойдёт до контроллера, обработка остановится на JwtFilter
22%
Выбросится FilterChainException
14%
Посмотреть ответ
👍3❤1🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
📅 Старт курса — 20 апреля.
Если хотите разобраться, как строить управляемые агентные системы:
P.S.
Please open Telegram to view this post
VIEW IN TELEGRAM
volatile – это ключевое слово, которое часто используют, но не до конца понимают. Обычно говорят, что оно гарантирует видимость изменений между потоками. На самом деле, смысл этого слова одновременно шире и уже, чем кажется.🔹 Проблема без volatile
Современные процессоры и компиляторы переупорядочивают инструкции для оптимизации. Каждое ядро имеет store buffer — запись в память не мгновенна, сначала попадает в буфер. Другое ядро может не увидеть запись ещё долгое время.
// Поток 1
data = 42;
ready = true;
// Поток 2
if (ready) {
System.out.println(data); // может напечатать 0
}
Без барьеров компилятор или процессор может переставить data = 42 и ready = true. Или поток 2 увидит ready = true из кеша раньше чем data = 42 из store buffer дойдёт до памяти.
🔹 Что на самом деле гарантирует volatile
Запись в volatile переменную
Сбрасывает store buffer. Все предыдущие записи этого потока становятся видимы другим потокам до того как запись в volatile будет видна.
Чтение volatile переменной
Инвалидирует локальный кеш. Поток видит актуальные значения всех записей, которые произошли до соответствующей volatile-записи в другом потоке.
Это и есть happens-before: если поток A записал в volatile переменную, а поток B прочитал это значение — всё что A делал до записи, видимо B после чтения.
volatile boolean ready;
int data; // не volatile!
// Поток 1
data = 42; // HB-предшествует записи в ready
ready = true; // volatile write
// Поток 2
if (ready) { // volatile read
// data гарантированно == 42
System.out.println(data);
}
data не volatile, но гарантия работает через happens-before цепочку.
🔹 Что volatile не гарантирует
Атомарность составных операций:
volatile long counter;
counter++; // не атомарно: read → increment → write
На 32-битных JVM даже чтение/запись long без volatile не атомарна (два 32-битных слова). volatile long делает операцию атомарной, но counter++ всё равно не атомарна как составная операция.
🔹 Модель памяти Java (JMM) и happens-before
JMM определяет happens-before не только для volatile. Полный список отношений:
— Запись в поле до разблокировки монитора HB разблокировке.
— Разблокировка монитора HB последующей блокировке того же монитора.
— Запись в volatile HB последующему чтению той же переменной.
— Завершение Thread.start() HB любому действию в запущенном потоке.
— Любое действие в потоке HB Thread.join() на этом потоке.
Эти правила транзитивны. Именно на этом строятся корректные публикации объектов: final поля объекта видны всем потокам без дополнительной синхронизации после завершения конструктора, потому что завершение конструктора HB любому доступу к объекту через корректно опубликованную ссылку.
🔹 StampedLock и оптимистичное чтение
StampedLock (Java 8+) предлагает три режима: запись, пессимистичное чтение, оптимистичное чтение. Оптимистичное чтение не берёт блокировку вообще — читает данные и потом валидирует что запись не произошла:long stamp = lock.tryOptimisticRead();
int x = point.x;
int y = point.y;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
x = point.x;
y = point.y;
} finally {
lock.unlockRead(stamp);
}
}
validate — это volatile-read под капотом, устанавливающий happens-before с последней записью. Паттерн работает корректно именно из-за JMM семантики, а не "просто так".══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤3🔥3
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17👍2👏2😢1
Когда список точно из одного элемента — не создавай изменяемый:
// ❌ Избыточно
List<String> roles = new ArrayList<>();
roles.add("ADMIN");
someMethod(roles);
// ✅ Лаконично и без лишней аллокации
someMethod(Collections.singletonList("ADMIN"));
singletonList возвращает неизменяемую обёртку вокруг одного объекта без внутреннего массива. Это дешевле по памяти и явно выражает намерение.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍3🔥2
Forwarded from Библиотека собеса по Java | вопросы с собеседований
Классическая ловушка в многопоточке👇
📦 Задание
Написали сервис для аудит-логирования действий пользователей. В проде периодически в лог пишется чужой userId — данные одного юзера попадают в запись другого. Найдите баг и исправьте:
@Component
public class UserContext {
private static final ThreadLocal<String> currentUserId = new ThreadLocal<>();
public static void set(String userId) { currentUserId.set(userId); }
public static String get() { return currentUserId.get(); }
public static void clear() { currentUserId.remove(); }
}
@Service
@RequiredArgsConstructor
public class OrderService {
private final AuditLogger auditLogger;
public CompletableFuture<Order> createOrder(String userId, OrderDto dto) {
UserContext.set(userId);
return CompletableFuture.supplyAsync(() -> {
Order order = buildOrder(dto);
auditLogger.log("Order created by: " + UserContext.get());
return order;
});
}
}
🔹 Задачи
— Объяснить, почему UserContext.get() внутри supplyAsync может вернуть чужой userId или null
— Исправить так, чтобы контекст корректно передавался в асинхронный поток
— Бонус: объяснить, почему ThreadLocal вообще опасен с пулами потоков типа ForkJoinPool
Ставьте → 🔥, если нравится формат. Если нет → 🌚
#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍5❤3
Простая команда на случай, когда надо быстро и в удобном формате прочитать CSV-файл в терминале:
$ cat inventory.csv | column -t -s,
Флаг
-s указывает на использование запятых в качестве разделителей, а -t форматирует выходные данные в чистую таблицу.══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥3
💥 Открытый вебинар | ИИ-агенты в продакшене: от хайпа к деньгам
Агенты уже везде. Но мало кто признаётся, сколько денег сжёг на бесконечных циклах, галлюцинациях в RAG и отсутствии мониторинга.
Полина Полунина, руководитель AI-направления Альфа-Банка, расскажет честно:
▪️ Чем агент отличается от «просто GPT с промптом» и когда бизнесу достаточно обычного LLM
▪️ 3 реальных кейса из корпоративной среды: что взлетело, а что нет
▪️ Live-демо работающего агента
▪️ ТОП-5 граблей, на которые наступают команды при внедрении
⏱️ 10 марта в 19:00 (МСК)
🎁 Участники получат промокод на скидку на самый полный курс по ИИ-агентам
👉 Регистрируйся
Агенты уже везде. Но мало кто признаётся, сколько денег сжёг на бесконечных циклах, галлюцинациях в RAG и отсутствии мониторинга.
Полина Полунина, руководитель AI-направления Альфа-Банка, расскажет честно:
▪️ Чем агент отличается от «просто GPT с промптом» и когда бизнесу достаточно обычного LLM
▪️ 3 реальных кейса из корпоративной среды: что взлетело, а что нет
▪️ Live-демо работающего агента
▪️ ТОП-5 граблей, на которые наступают команды при внедрении
⏱️ 10 марта в 19:00 (МСК)
🎁 Участники получат промокод на скидку на самый полный курс по ИИ-агентам
👉 Регистрируйся
🌸 Поздравляем с 8 марта
Дорогие девушки, кто выбрал этот безумный и прекрасный путь в IT. Спасибо, что вы есть в нашей профессии.
Пусть сегодня всё задуманное сбывается, улыбок будет больше, чем поводов для них, а день подарит только приятные сюрпризы!
С праздником, коллеги 💐
🐸 Библиотека джависта
Дорогие девушки, кто выбрал этот безумный и прекрасный путь в IT. Спасибо, что вы есть в нашей профессии.
Пусть сегодня всё задуманное сбывается, улыбок будет больше, чем поводов для них, а день подарит только приятные сюрпризы!
С праздником, коллеги 💐
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍3🔥2👾1
Если используешь Ctrl + P (подсказка параметров метода), то вот ещё один полезный хот кей: Shift + Ctrl + I → быстрый просмотр определения.
🔹 Зачем это нужно
— Позволяет посмотреть реализацию метода/класса/интерфейса без перехода в другой файл.
— Работает с любыми символами: методами, переменными, константами, даже SQL-мэпперами в MyBatis.
— Незаменимо, если не хочешь терять контекст текущего кода.
🔹 Как использовать
— Наведи курсор на метод, поле или класс, нажми Ctrl + Shift + I — появится всплывающее окно с реализацией.
— Работает и в дебаге, и при просмотре внешних библиотек (если есть исходники).
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥6❤3
Классическая проблема растущего проекта: сервис уведомлений начинает захлёбываться. В пике прилетает 10к запросов в секунду, а он обрабатывает 3к. Остальные просто теряются.
Можно горизонтально масштабировать, но это не решает проблему архитектурно. А Kafka решает.
Идея простая: Producer пишет, Consumer читает в своём темпе. Никто никого не ждёт. Никто никого не роняет.
@Service
@RequiredArgsConstructor
public class OrderService {
private final KafkaTemplate<String, OrderEvent> kafkaTemplate;
public void createOrder(Order order) {
orderRepository.save(order);
OrderEvent event = new OrderEvent(order.getId(), order.getUserId());
kafkaTemplate.send("order-created", order.getUserId().toString(), event);
// топик ключ партиции payload
}
}
Ключ партиции — важная деталь. Kafka гарантирует порядок сообщений внутри одной партиции. Если передаёшь
userId как ключ — все события одного пользователя попадут в одну партицию и будут обработаны строго по порядку.@Component
public class NotificationConsumer {
@KafkaListener(
topics = "order-created",
groupId = "notification-group",
concurrency = "3" // 3 потока = читаем 3 партиции параллельно
)
public void handle(OrderEvent event) {
notificationService.send(event.getUserId());
}
}
groupId определяет логическую группу потребителей. Kafka гарантирует: одно сообщение получит ровно один инстанс внутри группы. Хочешь, чтобы событие получили оба сервиса уведомлений и аналитики? Разные groupId и каждый читает топик независимо.
order-created (3 партиции)
├── partition-0 → consumer-instance-1
├── partition-1 → consumer-instance-2
└── partition-2 → consumer-instance-3
Не хватает скорости обработки → поднимаешь ещё инстансов. Kafka сама перераспределит партиции. Но инстансов больше, чем партиций держать смысла нет, лишние будут просто простаивать.
Kafka хранит сообщения на диске (по умолчанию 7 дней). Consumer сам трекает, до какого offset он дочитал.
spring:
kafka:
consumer:
auto-offset-reset: earliest # читать с начала, если offset не найден
enable-auto-commit: false # коммитим offset вручную — только после успешной обработки
enable-auto-commit: false — критически важная настройка. Если Consumer упал в середине обработки, он перечитает сообщения с последнего закоммиченного offset. При true — offset уже сдвинулся, сообщение потеряно.
Иногда одно сообщение падает раз за разом: битые данные, баг в логике. Consumer уходит в бесконечный retry и встаёт колом.
@Bean
public DefaultErrorHandler errorHandler(KafkaTemplate<String, Object> kafkaTemplate) {
var recoverer = new DeadLetterPublishingRecoverer(kafkaTemplate);
var backoff = new FixedBackOff(1000L, 3); // 3 попытки с паузой 1с
return new DefaultErrorHandler(recoverer, backoff);
}
После 3 неудачных попыток сообщение уедет в топик
order-created.DLT. Основной поток не заблокирован, разбираешься с проблемой отдельно.Нужен ответ прямо сейчас → REST
Получатель может быть недоступен → Kafka
Один источник и много потребителей → Kafka
Аудит и история событий → Kafka
Простой CRUD без нагрузки → REST
Kafka не серебряная пуля. Она добавляет операционную сложность: нужно думать об idempotency, порядке сообщений, мониторинге lag у Consumer-групп. Но когда система начинает терять данные под нагрузкой, цена этой сложности оправдана.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍5❤1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁24🙏3👍1
Spring Cloud Gateway — это API Gateway поверх Project Reactor. Маршрутизация запросов, балансировка нагрузки, rate limiting, аутентификация.
Реактивный, non-blocking, легко расширяемый через фильтры.
Добавьте spring-cloud-starter-gateway — это вытащит Reactor Netty как сервер. Важно: НЕ добавляйте spring-boot-starter-web, они несовместимы. Gateway работает на WebFlux стеке.
Для service discovery добавьте spring-cloud-starter-netflix-eureka-client или spring-cloud-starter-consul-discovery.
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
lb:// — это magic prefix для балансировки через service discovery. StripPrefix=1 срезает /api перед проксированием запроса вниз.
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest()
.getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION);
if (token == null || !isValid(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() { return -1; } // выполняется первым
}
getOrder() с отрицательным значением — фильтр выполнится до встроенных. Возвращайте chain.filter(exchange) чтобы пропустить запрос дальше.
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
);
}
replenishRate — токенов в секунду, burstCapacity — максимальный burst. Требует spring-boot-starter-data-redis-reactive.
filters:
- name: CircuitBreaker
args:
name: userServiceCB
fallbackUri: forward:/fallback/users
@RestController
public class FallbackController {
@GetMapping("/fallback/users")
public Mono<String> usersFallback() {
return Mono.just("Users service unavailable");
}
}
Circuit Breaker открывается при превышении порога ошибок и перенаправляет на fallback endpoint вместо каскадного падения.
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
Настраивайте CORS на уровне Gateway — не нужно дублировать это в каждом микросервисе.
Запрос приходит → RoutePredicateHandlerMapping матчит маршрут по predicates → цепочка GatewayFilter обрабатывает запрос → NettyRoutingFilter проксирует вниз → цепочка фильтров обрабатывает ответ в обратном порядке.
Всё это non-blocking на Project Reactor. Один поток может обрабатывать тысячи одновременных соединений.
💡 Бонус-совет
Actuator endpoint /actuator/gateway/routes покажет все зарегистрированные маршруты в runtime — удобно для дебага. Добавьте management.endpoint.gateway.enabled=true в конфиг и можно динамически обновлять маршруты через /actuator/gateway/refresh без перезапуска.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2❤1🎉1