Подробный разбор решения задачи Task211124_2
1. Контекст задачи:
Задача демонстрирует использование Spring Data JPA для работы с базой данных. В частности, она показывает, как использовать аннотации JPA (@Entity, @Table, @Id) для определения сущностей, а также JpaRepository для выполнения CRUD операций и запросов с использованием JPQL. Основное внимание уделяется выполнению операций сохранения и выборки данных.
2. Ключевые элементы кода:
Аннотация @SpringBootApplication:
Указывает, что класс Main211124_2 является главным классом Spring Boot приложения. Она включает в себя @Configuration, @EnableAutoConfiguration, и @ComponentScan, что автоматически настраивает компоненты Spring, включая Spring Data JPA.
Аннотация @Entity:
Класс User2111 помечен аннотацией @Entity, что указывает JPA, что этот класс соответствует таблице в базе данных. Он представляет собой сущность, с которой будет работать JPA.
Аннотация @Table(name = "users2111"):
Определяет, что эта сущность будет сопоставлена с таблицей users2111 в базе данных. Если аннотация @Table не указана, JPA по умолчанию использует имя класса как имя таблицы.
Аннотация @Id и @GeneratedValue:
Поле id помечено как первичный ключ с помощью аннотации @Id.
Аннотация @GeneratedValue(strategy = GenerationType.AUTO) указывает, что значение для поля id будет генерироваться автоматически (обычно с использованием автоинкремента в базе данных).
Интерфейс UserRepository2111 и аннотация @Repository:
UserRepository2111 расширяет JpaRepository, что предоставляет стандартные методы CRUD (например, save, findAll, deleteById).
Метод findByAgeGreaterThan(int age) позволяет выполнять JPQL-запрос для получения всех пользователей, у которых возраст больше заданного.
Использование CommandLineRunner:
CommandLineRunner используется для выполнения кода сразу после запуска приложения. В данном случае он выполняет следующие шаги:
Сохраняет в базу данных двух пользователей: "Alice" с возрастом 30 и "Bob" с возрастом 25.
Выполняет запрос findByAgeGreaterThan(20), возвращающий всех пользователей с возрастом больше 20.
Выводит имена выбранных пользователей в консоль.
3. Сценарий работы программы:
Запуск приложения:
Программа запускается с помощью SpringApplication.run(Main211124_2.class, args);. Spring Boot настраивает подключение к базе данных и компоненты Spring Data JPA.
Вставка данных:
Метод save() из JpaRepository используется для сохранения двух записей:
User2111("Alice", 30)
User2111("Bob", 25)
Выполнение запроса:
Метод findByAgeGreaterThan(20) выбирает всех пользователей, у которых возраст больше 20. Это JPQL-запрос, автоматически формируемый Spring Data JPA на основе имени метода.
Вывод данных:
Полученные записи проходят через метод forEach, который вызывает System.out.println для вывода имен в консоль.
4. Ключевые моменты и выводы:
Использование JPA и Spring Data:
Spring Data JPA значительно упрощает работу с базой данных, предоставляя готовые методы для выполнения CRUD операций и поддерживая создание запросов на основе имен методов.
Аннотации JPA:
@Entity и @Table используются для связывания класса с таблицей в базе данных.
@Id и @GeneratedValue обеспечивают автоматическую генерацию уникальных идентификаторов для каждой записи.
JPQL-запросы и JpaRepository:
Метод findByAgeGreaterThan демонстрирует, как можно выполнять запросы к базе данных, просто определяя метод с соответствующим именем в репозитории.
Гибкость CommandLineRunner:
Использование CommandLineRunner позволяет запускать код после загрузки контекста Spring, что удобно для тестирования операций с базой данных.
#Solution_TasksSpring
1. Контекст задачи:
Задача демонстрирует использование Spring Data JPA для работы с базой данных. В частности, она показывает, как использовать аннотации JPA (@Entity, @Table, @Id) для определения сущностей, а также JpaRepository для выполнения CRUD операций и запросов с использованием JPQL. Основное внимание уделяется выполнению операций сохранения и выборки данных.
2. Ключевые элементы кода:
Аннотация @SpringBootApplication:
Указывает, что класс Main211124_2 является главным классом Spring Boot приложения. Она включает в себя @Configuration, @EnableAutoConfiguration, и @ComponentScan, что автоматически настраивает компоненты Spring, включая Spring Data JPA.
Аннотация @Entity:
Класс User2111 помечен аннотацией @Entity, что указывает JPA, что этот класс соответствует таблице в базе данных. Он представляет собой сущность, с которой будет работать JPA.
Аннотация @Table(name = "users2111"):
Определяет, что эта сущность будет сопоставлена с таблицей users2111 в базе данных. Если аннотация @Table не указана, JPA по умолчанию использует имя класса как имя таблицы.
Аннотация @Id и @GeneratedValue:
Поле id помечено как первичный ключ с помощью аннотации @Id.
Аннотация @GeneratedValue(strategy = GenerationType.AUTO) указывает, что значение для поля id будет генерироваться автоматически (обычно с использованием автоинкремента в базе данных).
Интерфейс UserRepository2111 и аннотация @Repository:
UserRepository2111 расширяет JpaRepository, что предоставляет стандартные методы CRUD (например, save, findAll, deleteById).
Метод findByAgeGreaterThan(int age) позволяет выполнять JPQL-запрос для получения всех пользователей, у которых возраст больше заданного.
Использование CommandLineRunner:
CommandLineRunner используется для выполнения кода сразу после запуска приложения. В данном случае он выполняет следующие шаги:
Сохраняет в базу данных двух пользователей: "Alice" с возрастом 30 и "Bob" с возрастом 25.
Выполняет запрос findByAgeGreaterThan(20), возвращающий всех пользователей с возрастом больше 20.
Выводит имена выбранных пользователей в консоль.
3. Сценарий работы программы:
Запуск приложения:
Программа запускается с помощью SpringApplication.run(Main211124_2.class, args);. Spring Boot настраивает подключение к базе данных и компоненты Spring Data JPA.
Вставка данных:
Метод save() из JpaRepository используется для сохранения двух записей:
User2111("Alice", 30)
User2111("Bob", 25)
Выполнение запроса:
Метод findByAgeGreaterThan(20) выбирает всех пользователей, у которых возраст больше 20. Это JPQL-запрос, автоматически формируемый Spring Data JPA на основе имени метода.
Вывод данных:
Полученные записи проходят через метод forEach, который вызывает System.out.println для вывода имен в консоль.
4. Ключевые моменты и выводы:
Использование JPA и Spring Data:
Spring Data JPA значительно упрощает работу с базой данных, предоставляя готовые методы для выполнения CRUD операций и поддерживая создание запросов на основе имен методов.
Аннотации JPA:
@Entity и @Table используются для связывания класса с таблицей в базе данных.
@Id и @GeneratedValue обеспечивают автоматическую генерацию уникальных идентификаторов для каждой записи.
JPQL-запросы и JpaRepository:
Метод findByAgeGreaterThan демонстрирует, как можно выполнять запросы к базе данных, просто определяя метод с соответствующим именем в репозитории.
Гибкость CommandLineRunner:
Использование CommandLineRunner позволяет запускать код после загрузки контекста Spring, что удобно для тестирования операций с базой данных.
#Solution_TasksSpring
Транзакции в Spring
В современных приложениях, особенно тех, что работают с базами данных, транзакции играют ключевую роль. Они обеспечивают выполнение операций в базе данных с гарантией целостности данных и устойчивости к сбоям.
Транзакция — это последовательность операций, которые выполняются как единое целое. Если хотя бы одна из операций в транзакции завершается с ошибкой, все изменения, сделанные в рамках этой транзакции, откатываются.
Ключевые свойства транзакций определяются через ACID:
Atomicity (Атомарность): Все операции в транзакции выполняются или ни одна из них.
Consistency (Согласованность): Транзакция переводит базу данных из одного согласованного состояния в другое.
Isolation (Изолированность): Операции в транзакции не видимы другим транзакциям, пока они не завершатся.
Durability (Устойчивость): После успешного завершения транзакции изменения остаются сохраненными в базе данных, даже в случае сбоя системы.
Пример транзакции в SQL
Предположим, у нас есть две таблицы: accounts и transactions. Нам нужно перевести деньги с одного счета на другой.
Транзакции в Spring
Spring обеспечивает управление транзакциями с помощью своих инструментов.
В экосистеме Spring можно использовать различные подходы:
Программное управление транзакциями — требуется вручную управлять началом и завершением транзакций.
Декларативное управление транзакциями — управление транзакциями осуществляется автоматически с помощью аннотаций или конфигураций. Этот подход является наиболее популярным, так как упрощает код.
Программное управление транзакциями
Для ручного управления транзакциями в Spring используется PlatformTransactionManager.
Пример:
Декларативное управление транзакциями
Более простой и популярный способ — это использование аннотации @Transactional.
Преимущества транзакций:
Целостность данных: Транзакции гарантируют, что данные останутся в корректном состоянии.
Стабильность системы: Операции либо полностью завершаются, либо полностью откатываются.
Упрощение отладки: Вы можете быть уверены, что в случае сбоя данные не будут повреждены.
#Java #Training #Spring #Transactions #ACID
В современных приложениях, особенно тех, что работают с базами данных, транзакции играют ключевую роль. Они обеспечивают выполнение операций в базе данных с гарантией целостности данных и устойчивости к сбоям.
Транзакция — это последовательность операций, которые выполняются как единое целое. Если хотя бы одна из операций в транзакции завершается с ошибкой, все изменения, сделанные в рамках этой транзакции, откатываются.
Ключевые свойства транзакций определяются через ACID:
Atomicity (Атомарность): Все операции в транзакции выполняются или ни одна из них.
Consistency (Согласованность): Транзакция переводит базу данных из одного согласованного состояния в другое.
Isolation (Изолированность): Операции в транзакции не видимы другим транзакциям, пока они не завершатся.
Durability (Устойчивость): После успешного завершения транзакции изменения остаются сохраненными в базе данных, даже в случае сбоя системы.
Пример транзакции в SQL
Предположим, у нас есть две таблицы: accounts и transactions. Нам нужно перевести деньги с одного счета на другой.
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
INSERT INTO transactions (from_account, to_account, amount) VALUES (1, 2, 100);
COMMIT;
Если любая из этих операций не выполняется, все изменения откатываются.
Транзакции в Spring
Spring обеспечивает управление транзакциями с помощью своих инструментов.
В экосистеме Spring можно использовать различные подходы:
Программное управление транзакциями — требуется вручную управлять началом и завершением транзакций.
Декларативное управление транзакциями — управление транзакциями осуществляется автоматически с помощью аннотаций или конфигураций. Этот подход является наиболее популярным, так как упрощает код.
Программное управление транзакциями
Для ручного управления транзакциями в Spring используется PlatformTransactionManager.
Пример:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class TransactionalService {
@Autowired
private PlatformTransactionManager transactionManager;
public void performTransactionalOperation() {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// Ваши операции с базой данных
performDatabaseOperation1();
performDatabaseOperation2();
// Подтверждение транзакции
transactionManager.commit(status);
} catch (Exception e) {
// Откат транзакции в случае ошибки
transactionManager.rollback(status);
throw e;
}
}
private void performDatabaseOperation1() {
// Код операции 1
}
private void performDatabaseOperation2() {
// Код операции 2
}
}
Этот метод предоставляет полный контроль над транзакциями, но делает код более сложным.
Декларативное управление транзакциями
Более простой и популярный способ — это использование аннотации @Transactional.
Преимущества транзакций:
Целостность данных: Транзакции гарантируют, что данные останутся в корректном состоянии.
Стабильность системы: Операции либо полностью завершаются, либо полностью откатываются.
Упрощение отладки: Вы можете быть уверены, что в случае сбоя данные не будут повреждены.
#Java #Training #Spring #Transactions #ACID
Продолжаем устранять пробелы в многопоточке Java. Сегодня рассмотрим Semaphore и CountDownLatch.
Semaphore
Semaphore используется для управления доступом к ограниченному ресурсу, который может одновременно использоваться только определенным числом потоков. Это полезно для реализации пула ресурсов, например, подключения к базе данных, файловых дескрипторов и других ограниченных ресурсов.
Основные методы Semaphore
acquire(): Захватывает разрешение (пермит). Если разрешений нет, поток блокируется до тех пор, пока одно из них не станет доступным.
acquire(int permits): Захватывает указанное количество разрешений. Если их недостаточно, поток блокируется.
release(): Освобождает разрешение, увеличивая количество доступных разрешений на 1.
release(int permits): Освобождает указанное количество разрешений.
availablePermits(): Возвращает количество доступных разрешений.
tryAcquire(): Пытается захватить разрешение. Возвращает true, если удалось получить разрешение, иначе false.
tryAcquire(int permits, long timeout, TimeUnit unit): Пытается получить разрешения с указанным временем ожидания.
isFair(): Проверяет, использует ли семафор справедливый порядок захвата разрешений (FIFO).
Типы Semaphore
Несправедливый (non-fair): Потоки получают доступ в произвольном порядке (по умолчанию).
Справедливый (fair): Потоки получают доступ в порядке очереди (FIFO).
Пример использования Semaphore
Результат:
В каждый момент времени только 2 потока выполняют свою работу.
Остальные ждут освобождения разрешения.
Нюансы Semaphore
Справедливость (fair vs non-fair):
Несправедливый семафор быстрее, но поток может быть отложен, даже если он ожидает дольше других.
Справедливый семафор обеспечивает порядок очереди, но имеет больше накладных расходов.
Deadlock (взаимная блокировка):
Если поток забывает вызвать release() после acquire(), это приведет к "утечке" разрешений.
Пул ресурсов:
Часто используется для ограничения числа потоков, работающих с одним и тем же ресурсом.
#Java #Training #Multithreading #Semaphore
Semaphore
Semaphore используется для управления доступом к ограниченному ресурсу, который может одновременно использоваться только определенным числом потоков. Это полезно для реализации пула ресурсов, например, подключения к базе данных, файловых дескрипторов и других ограниченных ресурсов.
Основные методы Semaphore
acquire(): Захватывает разрешение (пермит). Если разрешений нет, поток блокируется до тех пор, пока одно из них не станет доступным.
acquire(int permits): Захватывает указанное количество разрешений. Если их недостаточно, поток блокируется.
release(): Освобождает разрешение, увеличивая количество доступных разрешений на 1.
release(int permits): Освобождает указанное количество разрешений.
availablePermits(): Возвращает количество доступных разрешений.
tryAcquire(): Пытается захватить разрешение. Возвращает true, если удалось получить разрешение, иначе false.
tryAcquire(int permits, long timeout, TimeUnit unit): Пытается получить разрешения с указанным временем ожидания.
isFair(): Проверяет, использует ли семафор справедливый порядок захвата разрешений (FIFO).
Типы Semaphore
Несправедливый (non-fair): Потоки получают доступ в произвольном порядке (по умолчанию).
Справедливый (fair): Потоки получают доступ в порядке очереди (FIFO).
Пример использования Semaphore
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
// Семафор с 2 разрешениями
Semaphore semaphore = new Semaphore(2);
// Пул из 5 потоков
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
final int threadId = i;
executor.submit(() -> {
try {
System.out.println("Thread " + threadId + " is waiting for permit...");
semaphore.acquire(); // Получаем разрешение
System.out.println("Thread " + threadId + " acquired permit.");
Thread.sleep(2000); // Имитируем использование ресурса
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
System.out.println("Thread " + threadId + " released permit.");
semaphore.release(); // Освобождаем разрешение
}
});
}
executor.shutdown();
}
}
Результат:
В каждый момент времени только 2 потока выполняют свою работу.
Остальные ждут освобождения разрешения.
Нюансы Semaphore
Справедливость (fair vs non-fair):
Несправедливый семафор быстрее, но поток может быть отложен, даже если он ожидает дольше других.
Справедливый семафор обеспечивает порядок очереди, но имеет больше накладных расходов.
Deadlock (взаимная блокировка):
Если поток забывает вызвать release() после acquire(), это приведет к "утечке" разрешений.
Пул ресурсов:
Часто используется для ограничения числа потоков, работающих с одним и тем же ресурсом.
#Java #Training #Multithreading #Semaphore
CountDownLatch
CountDownLatch используется для обеспечения синхронизации между потоками, позволяя одному или нескольким потокам ждать завершения операций в других потоках.
Основные методы CountDownLatch
await(): Блокирует поток до тех пор, пока счетчик не станет равен 0.
countDown(): Уменьшает значение счетчика на 1.
getCount(): Возвращает текущее значение счетчика.
await(long timeout, TimeUnit unit): Ждет заданное время. Если счетчик не достигает 0 за указанное время, поток продолжит выполнение.
Пример использования CountDownLatch
Результат:
Основной поток будет ждать завершения всех 3 задач.
После выполнения всех потоков (latch.countDown() вызывается 3 раза), основной поток продолжит выполнение.
Нюансы CountDownLatch
Одноразовый:
CountDownLatch нельзя сбросить или переиспользовать. Если нужно использовать его несколько раз, рассмотрите использование CyclicBarrier.
Потокобезопасность:
Все методы потокобезопасны и могут использоваться несколькими потоками одновременно.
Применение:
Инициализация или подготовка перед началом основной работы.
Ожидание завершения группы задач.
Когда использовать Semaphore или CountDownLatch?
Используйте Semaphore, если нужно управлять доступом к ограниченным ресурсам (например, пул соединений).
Используйте CountDownLatch, если потоки должны дождаться выполнения определенного количества задач, прежде чем продолжить выполнение.
Реальные примеры
Semaphore: Ограничение количества одновременных соединений
CountDownLatch: Ожидание завершения загрузки данных
#Java #Training #Multithreading #CountDownLatch
CountDownLatch используется для обеспечения синхронизации между потоками, позволяя одному или нескольким потокам ждать завершения операций в других потоках.
Основные методы CountDownLatch
await(): Блокирует поток до тех пор, пока счетчик не станет равен 0.
countDown(): Уменьшает значение счетчика на 1.
getCount(): Возвращает текущее значение счетчика.
await(long timeout, TimeUnit unit): Ждет заданное время. Если счетчик не достигает 0 за указанное время, поток продолжит выполнение.
Пример использования CountDownLatch
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
// Создаем CountDownLatch с начальным значением 3
CountDownLatch latch = new CountDownLatch(3);
// Потоки, выполняющие задачи
Runnable task = () -> {
System.out.println(Thread.currentThread().getName() + " is working...");
try {
Thread.sleep(1000); // Имитация работы
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " finished.");
latch.countDown(); // Уменьшаем значение счетчика
};
// Запускаем 3 потока
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
System.out.println("Main thread is waiting for tasks to finish...");
latch.await(); // Ждем, пока счетчик не станет равен 0
System.out.println("All tasks are finished. Main thread resumes.");
}
}
Результат:
Основной поток будет ждать завершения всех 3 задач.
После выполнения всех потоков (latch.countDown() вызывается 3 раза), основной поток продолжит выполнение.
Нюансы CountDownLatch
Одноразовый:
CountDownLatch нельзя сбросить или переиспользовать. Если нужно использовать его несколько раз, рассмотрите использование CyclicBarrier.
Потокобезопасность:
Все методы потокобезопасны и могут использоваться несколькими потоками одновременно.
Применение:
Инициализация или подготовка перед началом основной работы.
Ожидание завершения группы задач.
Когда использовать Semaphore или CountDownLatch?
Используйте Semaphore, если нужно управлять доступом к ограниченным ресурсам (например, пул соединений).
Используйте CountDownLatch, если потоки должны дождаться выполнения определенного количества задач, прежде чем продолжить выполнение.
Реальные примеры
Semaphore: Ограничение количества одновременных соединений
Semaphore semaphore = new Semaphore(10); // Максимум 10 соединений
// Каждый поток пытается установить соединение
Runnable connectTask = () -> {
try {
semaphore.acquire();
System.out.println("Connection established by " + Thread.currentThread().getName());
Thread.sleep(2000); // Используем соединение
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
System.out.println("Connection released by " + Thread.currentThread().getName());
semaphore.release();
}
};
CountDownLatch: Ожидание завершения загрузки данных
CountDownLatch latch = new CountDownLatch(3);
Runnable loadData = () -> {
try {
System.out.println(Thread.currentThread().getName() + " loading data...");
Thread.sleep(1000);
latch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
new Thread(loadData).start();
new Thread(loadData).start();
new Thread(loadData).start();
latch.await();
System.out.println("All data loaded. Proceeding to next step.");
#Java #Training #Multithreading #CountDownLatch
Что выведет код?
#Tasks
public class Task221124_1 {
public static void main(String[] args) {
int[] arr = {3, 5, 7, 9, 11};
int result = modifyArray(arr);
System.out.println(result);
System.out.println(arr[1]);
}
public static int modifyArray(int[] array) {
int sum = 0;
for (int i = 0; i < array.length; i++) {
array[i] = array[i] % 2 == 0 ? array[i] / 2 : array[i] * 2;
sum += array[i];
}
return sum;
}
}
#Tasks
Аннотация @Transactional
Spring предлагает удобный способ работы с транзакциями через аннотацию @Transactional. Она позволяет использовать декларативное управление транзакциями, минимизируя количество кода и повышая читаемость.
@Transactional — это аннотация, которая может быть применена к классу или методу, чтобы указать, что в рамках данного метода или всех методов класса должна использоваться транзакция.
Пример базового использования:
Основные параметры @Transactional
@Transactional поддерживает ряд параметров, которые позволяют гибко управлять транзакциями:
propagation: Определяет, как должна быть организована транзакция при вызове метода.
REQUIRED (по умолчанию): Использует текущую транзакцию или создает новую.
REQUIRES_NEW: Всегда создает новую транзакцию.
NESTED: Создает вложенную транзакцию.
SUPPORTS: Метод может работать в контексте транзакции, но это не обязательно.
isolation: Уровень изоляции транзакции.
READ_UNCOMMITTED: Минимальная изоляция, данные могут быть "грязными".
READ_COMMITTED: Предотвращает "грязное" чтение.
REPEATABLE_READ: Предотвращает неповторяющееся чтение.
SERIALIZABLE: Максимальная изоляция, предотвращает все виды конфликтов.
timeout: Максимальное время выполнения транзакции в секундах.
readOnly: Указывает, что транзакция предназначена только для чтения данных.
rollbackFor и noRollbackFor: Исключения, при которых следует или не следует откатывать транзакцию.
Пример с параметрами:
Управление откатами
Spring автоматически откатывает транзакции, если метод генерирует RuntimeException или Error. Вы можете настроить это поведение с помощью rollbackFor.
Применение @Transactional на уровне класса
Если аннотация используется на уровне класса, все методы будут выполняться в рамках транзакции.
Особенности работы с @Transactional
Прокси: Spring использует прокси-объекты для управления транзакциями. Это означает, что вызовы методов внутри одного класса могут не учитывать аннотацию @Transactional.
Пример проблемы:
#Java #Training #Spring #Transactional
Spring предлагает удобный способ работы с транзакциями через аннотацию @Transactional. Она позволяет использовать декларативное управление транзакциями, минимизируя количество кода и повышая читаемость.
@Transactional — это аннотация, которая может быть применена к классу или методу, чтобы указать, что в рамках данного метода или всех методов класса должна использоваться транзакция.
Пример базового использования:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class PaymentService {
@Transactional
public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
// Операции с базой данных
debitAccount(fromAccountId, amount);
creditAccount(toAccountId, amount);
}
private void debitAccount(Long accountId, double amount) {
// Логика снятия средств
}
private void creditAccount(Long accountId, double amount) {
// Логика зачисления средств
}
}
В этом примере все операции внутри метода transferMoney выполняются в одной транзакции. Если любая операция завершится сбоем, все изменения будут откатаны.
Основные параметры @Transactional
@Transactional поддерживает ряд параметров, которые позволяют гибко управлять транзакциями:
propagation: Определяет, как должна быть организована транзакция при вызове метода.
REQUIRED (по умолчанию): Использует текущую транзакцию или создает новую.
REQUIRES_NEW: Всегда создает новую транзакцию.
NESTED: Создает вложенную транзакцию.
SUPPORTS: Метод может работать в контексте транзакции, но это не обязательно.
isolation: Уровень изоляции транзакции.
READ_UNCOMMITTED: Минимальная изоляция, данные могут быть "грязными".
READ_COMMITTED: Предотвращает "грязное" чтение.
REPEATABLE_READ: Предотвращает неповторяющееся чтение.
SERIALIZABLE: Максимальная изоляция, предотвращает все виды конфликтов.
timeout: Максимальное время выполнения транзакции в секундах.
readOnly: Указывает, что транзакция предназначена только для чтения данных.
rollbackFor и noRollbackFor: Исключения, при которых следует или не следует откатывать транзакцию.
Пример с параметрами:
@Transactional(
propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.SERIALIZABLE,
timeout = 30,
rollbackFor = {RuntimeException.class},
readOnly = false
)
public void processTransaction() {
// Логика транзакции
}
Управление откатами
Spring автоматически откатывает транзакции, если метод генерирует RuntimeException или Error. Вы можете настроить это поведение с помощью rollbackFor.
@Transactional(rollbackFor = Exception.class)
public void updateDatabase() throws Exception {
// Если возникает Exception, транзакция будет откатана
}
Применение @Transactional на уровне класса
Если аннотация используется на уровне класса, все методы будут выполняться в рамках транзакции.
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class OrderService {
public void createOrder() {
// Операции в транзакции
}
public void cancelOrder() {
// Операции в транзакции
}
}
Особенности работы с @Transactional
Прокси: Spring использует прокси-объекты для управления транзакциями. Это означает, что вызовы методов внутри одного класса могут не учитывать аннотацию @Transactional.
Пример проблемы:
@Service
public class ExampleService {
@Transactional
public void method1() {
method2(); // method2 вызван напрямую, @Transactional не применяется
}
@Transactional
public void method2() {
// Логика method2
}
}
Только публичные методы: Аннотация работает только на публичных методах. Внутренние вызовы приватных или protected методов не активируют транзакцию.
#Java #Training #Spring #Transactional
Всем доброго субботнего утра!✌️
Вот и пришли выходные, а с ними и завтрашний лайф-кодинг.
В этот раз мы напишем на Spring простой банковский сервис, главной фишкой которого является асинхронная обработка всех поступающих запросов на перевод денег между клиентами.
Также в рамках написания, мы рассмотрим основные вопросы многопоточноcти в Java.
А в остальном всем теплых и светлых выходных!🫡
Вот и пришли выходные, а с ними и завтрашний лайф-кодинг.
В этот раз мы напишем на Spring простой банковский сервис, главной фишкой которого является асинхронная обработка всех поступающих запросов на перевод денег между клиентами.
Также в рамках написания, мы рассмотрим основные вопросы многопоточноcти в Java.
А в остальном всем теплых и светлых выходных!🫡
This media is not supported in your browser
VIEW IN TELEGRAM
Всем привет!🖐
Сегодня в 16:00 по МСК жду Вас на лайф-кодинге! 😱
Напишем на Spring простое банковское CRUD-приложение с упором на многопоточку и протестируем его.
Ссылку на Яндекс.Телемост опубликую здесь за 15 минут до начала.✌️
До встречи!🤓
Сегодня в 16:00 по МСК жду Вас на лайф-кодинге! 😱
Напишем на Spring простое банковское CRUD-приложение с упором на многопоточку и протестируем его.
Ссылку на Яндекс.Телемост опубликую здесь за 15 минут до начала.✌️
До встречи!🤓
Оглавление обучающих постов часть 3. SPRING
Spring Framework
Архитектура Spring и его модули
Spring Framework's
Контейнер Inversion of Control (IoC)
Принципы Dependency Injection (DI)
Управление объектами в Spring Container
Конфигурация Spring через XML
Конфигурация Spring через аннотации
Основы Bean в Spring: создание и управление
Жизненный цикл бинов
Синглтон и Прототипы в Spring
Паттерны использования бинов в Spring
Spring. Внедрение зависимостей через конструктор
Spring. Внедрение зависимостей через сеттеры
@Autowired
@Qualifier
Контекст Spring: ApplicationContext и BeanFactory
Способы загрузки контекста в Spring
Жизненный цикл ApplicationContext в Spring
Построение приложения с использованием Java-конфигурации в Spring
@Component и @Service
@Repository в Spring
Способы работы с внешними конфигурациями в Spring: application.properties и application.yml
Валидация и валидационные аннотации в Spring
@Import
@Value
——SPRING MVC——
Spring MVC
Архитектура MVC в Spring
@Controller
@RequestMapping
@GetMapping, @PostMapping, @PutMapping и @DeleteMapping
@RequestBody
@ModelAttribute
@RequestParam и @PathVariable
ViewResolver
@ResponseBody
Как @RestController взаимодействует с @RequestMapping
JSP и Thymeleaf как механизмы представления
Конфигурация шаблонов Thymeleaf в Spring
Формы и отправка данных в Spring MVC
Обработка форм и привязка данных в Spring MVC
@ExceptionHandler
@ControllerAdvice
——SPRING JDBC——
Введение в Spring JDBC
Настройка DataSource и подключение к базе данных в Spring JDBC
Использование JdbcTemplate в Spring JDBC для выполнения SQL-запросов
Создание и выполнение CRUD операций через Spring JDBC
Введение в ORM и Spring Data JPA
@Entity, @Table, @Id
@Column, @GeneratedValue, @ManyToOne
@OneToOne, @ManyToMany, @JoinColumn, @Lob, @Query, @Modifying, @EnableJpaRepositories
@Embeddable, @Embedded, @ElementCollection, @Inheritance, @Cacheable, @Lock, @EntityListeners, @SQLInsert, @SQLUpdate, @SQLDelete
Сущности в JPA
Репозитории в Spring Data: интерфейс CrudRepository и JpaRepository
Создание методов для поиска данных в Spring Data JPA
Транзакции в Spring
@Transactional
Уровни изоляции транзакций и виды проблем
Управление транзакциями вручную
Rollback и Commit транзакций
Rollback с использованием @Transactional
Исключения в транзакциях
Оптимизация работы с транзакциями
Нюансы работы с транзакциями в Spring
#Contents
Spring Framework
Архитектура Spring и его модули
Spring Framework's
Контейнер Inversion of Control (IoC)
Принципы Dependency Injection (DI)
Управление объектами в Spring Container
Конфигурация Spring через XML
Конфигурация Spring через аннотации
Основы Bean в Spring: создание и управление
Жизненный цикл бинов
Синглтон и Прототипы в Spring
Паттерны использования бинов в Spring
Spring. Внедрение зависимостей через конструктор
Spring. Внедрение зависимостей через сеттеры
@Autowired
@Qualifier
Контекст Spring: ApplicationContext и BeanFactory
Способы загрузки контекста в Spring
Жизненный цикл ApplicationContext в Spring
Построение приложения с использованием Java-конфигурации в Spring
@Component и @Service
@Repository в Spring
Способы работы с внешними конфигурациями в Spring: application.properties и application.yml
Валидация и валидационные аннотации в Spring
@Import
@Value
——SPRING MVC——
Spring MVC
Архитектура MVC в Spring
@Controller
@RequestMapping
@GetMapping, @PostMapping, @PutMapping и @DeleteMapping
@RequestBody
@ModelAttribute
@RequestParam и @PathVariable
ViewResolver
@ResponseBody
Как @RestController взаимодействует с @RequestMapping
JSP и Thymeleaf как механизмы представления
Конфигурация шаблонов Thymeleaf в Spring
Формы и отправка данных в Spring MVC
Обработка форм и привязка данных в Spring MVC
@ExceptionHandler
@ControllerAdvice
——SPRING JDBC——
Введение в Spring JDBC
Настройка DataSource и подключение к базе данных в Spring JDBC
Использование JdbcTemplate в Spring JDBC для выполнения SQL-запросов
Создание и выполнение CRUD операций через Spring JDBC
Введение в ORM и Spring Data JPA
@Entity, @Table, @Id
@Column, @GeneratedValue, @ManyToOne
@OneToOne, @ManyToMany, @JoinColumn, @Lob, @Query, @Modifying, @EnableJpaRepositories
@Embeddable, @Embedded, @ElementCollection, @Inheritance, @Cacheable, @Lock, @EntityListeners, @SQLInsert, @SQLUpdate, @SQLDelete
Сущности в JPA
Репозитории в Spring Data: интерфейс CrudRepository и JpaRepository
Создание методов для поиска данных в Spring Data JPA
Транзакции в Spring
@Transactional
Уровни изоляции транзакций и виды проблем
Управление транзакциями вручную
Rollback и Commit транзакций
Rollback с использованием @Transactional
Исключения в транзакциях
Оптимизация работы с транзакциями
Нюансы работы с транзакциями в Spring
#Contents
Оглавление для обучающих постов.
Если хотите найти информацию по Java, ранее опубликованную на канале - для Вас подготовлено оглавление уже из 3-х частей!
Пользуйтесь на здоровье!🫡
Часть 1.
Часть 2.
Часть 3. SPRING
Часть 2 дополнена.
Читайте, используйте, будут вопросы - пишите!😉
Если хотите найти информацию по Java, ранее опубликованную на канале - для Вас подготовлено оглавление уже из 3-х частей!
Пользуйтесь на здоровье!🫡
Часть 1.
Часть 2.
Часть 3. SPRING
Часть 2 дополнена.
Читайте, используйте, будут вопросы - пишите!😉
Простое Web приложение с асинхронной работой методов на Spring. Встреча от 24.11.2024
Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE
Спасибо всем кто пришел, за участие!💪
На сегодняшней встрече мы на примере, написали простое банковское Web приложение с асинхронной работой метода перевода денег на Spring. Дополнительно к постам в канале коротко разобрали работу каждой использованной аннотации, класса и метода.
Кроме того в тесте к данному приложению рассмотрели различные варианты использования методов многопоточности.
Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!
Ссылка на GitHub - https://github.com/Oleborn/MultiThreadingSpringApp
Всем хорошего настроения! 🫡✌️
Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE
Спасибо всем кто пришел, за участие!💪
На сегодняшней встрече мы на примере, написали простое банковское Web приложение с асинхронной работой метода перевода денег на Spring. Дополнительно к постам в канале коротко разобрали работу каждой использованной аннотации, класса и метода.
Кроме того в тесте к данному приложению рассмотрели различные варианты использования методов многопоточности.
Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!
Ссылка на GitHub - https://github.com/Oleborn/MultiThreadingSpringApp
Всем хорошего настроения! 🫡✌️
Уровни изоляции транзакций и виды проблем
Когда несколько транзакций работают одновременно, необходимо обеспечить согласованность данных. Для этого в реляционных базах данных применяются уровни изоляции. Они определяют, каким образом одна транзакция видит изменения, сделанные другой.
Уровни изоляции транзакций
SQL определяет четыре уровня изоляции. Каждый из них предлагает определенный баланс между производительностью и уровнем защиты от проблем параллелизма:
READ UNCOMMITTED (чтение незафиксированных данных)
Самый низкий уровень изоляции.
Транзакция может читать данные, которые еще не зафиксированы другой транзакцией.
Возможные проблемы: грязное чтение.
READ COMMITTED (чтение зафиксированных данных)
Гарантирует, что транзакция читает только данные, которые были зафиксированы.
Предотвращает грязное чтение, но не решает проблему неповторяемого чтения.
REPEATABLE READ (повторяемое чтение)
Обеспечивает, что данные, прочитанные в рамках транзакции, не изменятся, пока она не завершится.
Предотвращает грязное чтение и неповторяемое чтение, но не защищает от фантомных чтений.
SERIALIZABLE (серилизуемость)
Самый высокий уровень изоляции.
Транзакции выполняются последовательно, исключая все проблемы параллелизма.
Самый дорогой уровень с точки зрения производительности.
Виды проблем параллелизма
Грязное чтение (Dirty Read)
Одна транзакция читает данные, которые были изменены другой транзакцией, но не зафиксированы. Если вторая транзакция откатится, первая окажется с некорректными данными.
Неповторяемое чтение (Non-repeatable Read)
Данные, прочитанные одной транзакцией, могут быть изменены другой транзакцией до завершения первой.
Фантомное чтение (Phantom Read)
Транзакция читает набор строк, но другой транзакцией в этот набор добавляются новые строки.
Установка уровней изоляции в Spring
Уровень изоляции можно задать с помощью аннотации @Transactional:
Spring поддерживает следующие уровни:
Isolation.READ_UNCOMMITTED
Isolation.READ_COMMITTED
Isolation.REPEATABLE_READ
Isolation.SERIALIZABLE
#Java #Training #Spring #Isolation_Levels
Когда несколько транзакций работают одновременно, необходимо обеспечить согласованность данных. Для этого в реляционных базах данных применяются уровни изоляции. Они определяют, каким образом одна транзакция видит изменения, сделанные другой.
Уровни изоляции транзакций
SQL определяет четыре уровня изоляции. Каждый из них предлагает определенный баланс между производительностью и уровнем защиты от проблем параллелизма:
READ UNCOMMITTED (чтение незафиксированных данных)
Самый низкий уровень изоляции.
Транзакция может читать данные, которые еще не зафиксированы другой транзакцией.
Возможные проблемы: грязное чтение.
READ COMMITTED (чтение зафиксированных данных)
Гарантирует, что транзакция читает только данные, которые были зафиксированы.
Предотвращает грязное чтение, но не решает проблему неповторяемого чтения.
REPEATABLE READ (повторяемое чтение)
Обеспечивает, что данные, прочитанные в рамках транзакции, не изменятся, пока она не завершится.
Предотвращает грязное чтение и неповторяемое чтение, но не защищает от фантомных чтений.
SERIALIZABLE (серилизуемость)
Самый высокий уровень изоляции.
Транзакции выполняются последовательно, исключая все проблемы параллелизма.
Самый дорогой уровень с точки зрения производительности.
Виды проблем параллелизма
Грязное чтение (Dirty Read)
Одна транзакция читает данные, которые были изменены другой транзакцией, но не зафиксированы. Если вторая транзакция откатится, первая окажется с некорректными данными.
// Транзакция 1
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
// Транзакция 2 (до фиксации транзакции 1)
SELECT balance FROM accounts WHERE id = 1;
Неповторяемое чтение (Non-repeatable Read)
Данные, прочитанные одной транзакцией, могут быть изменены другой транзакцией до завершения первой.
// Транзакция 1
SELECT balance FROM accounts WHERE id = 1;
// Транзакция 2
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
// Транзакция 1 (повторное чтение)
SELECT balance FROM accounts WHERE id = 1;
Фантомное чтение (Phantom Read)
Транзакция читает набор строк, но другой транзакцией в этот набор добавляются новые строки.
// Транзакция 1
SELECT * FROM orders WHERE amount > 100;
// Транзакция 2
INSERT INTO orders (id, amount) VALUES (10, 150);
// Транзакция 1 (повторное чтение)
SELECT * FROM orders WHERE amount > 100;
Установка уровней изоляции в Spring
Уровень изоляции можно задать с помощью аннотации @Transactional:
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Transactional(isolation = Isolation.READ_COMMITTED)
public void processOrder() {
// Логика обработки заказа
}
}
Spring поддерживает следующие уровни:
Isolation.READ_UNCOMMITTED
Isolation.READ_COMMITTED
Isolation.REPEATABLE_READ
Isolation.SERIALIZABLE
#Java #Training #Spring #Isolation_Levels
Что выведет код?
#Tasks
public class Task251124_1 {
public static void main(String[] args) {
String str = "aabbccddeeff";
String result = str.replace("aa", "x")
.replace("ee", "y")
.replace("xx", "z")
.replace("dd", "w");
System.out.println(result);
}
}
#Tasks
Управление транзакциями вручную
Хотя Spring предоставляет удобный механизм декларативного управления транзакциями с помощью @Transactional, иногда требуется более тонкий контроль. В таких случаях используется ручное управление транзакциями.
Ручное управление транзакциями
Для ручного управления транзакциями в Spring используется интерфейс PlatformTransactionManager и его реализации, такие как DataSourceTransactionManager или JpaTransactionManager.
Пример: Использование PlatformTransactionManager
Программное управление в сочетании с TransactionTemplate
Spring предоставляет еще один инструмент для управления транзакциями вручную — TransactionTemplate. Это упрощает управление транзакциями за счет предоставления шаблонного метода для выполнения кода.
Пример с использованием TransactionTemplate:
#Java #Training #Spring #ManualTransactionService
Хотя Spring предоставляет удобный механизм декларативного управления транзакциями с помощью @Transactional, иногда требуется более тонкий контроль. В таких случаях используется ручное управление транзакциями.
Ручное управление транзакциями
Для ручного управления транзакциями в Spring используется интерфейс PlatformTransactionManager и его реализации, такие как DataSourceTransactionManager или JpaTransactionManager.
Пример: Использование PlatformTransactionManager
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class ManualTransactionService {
@Autowired
private PlatformTransactionManager transactionManager;
public void performManualTransaction() {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("CustomTransaction");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// Выполнение операций в транзакции
performDatabaseOperation1();
performDatabaseOperation2();
// Фиксация транзакции
transactionManager.commit(status);
} catch (Exception ex) {
// Откат транзакции в случае ошибки
transactionManager.rollback(status);
throw ex;
}
}
private void performDatabaseOperation1() {
// Логика операции 1
}
private void performDatabaseOperation2() {
// Логика операции 2
}
}
В этом примере транзакция начинается вручную, и ее выполнение зависит от логики программы. Если возникает ошибка, транзакция откатывается.
Программное управление в сочетании с TransactionTemplate
Spring предоставляет еще один инструмент для управления транзакциями вручную — TransactionTemplate. Это упрощает управление транзакциями за счет предоставления шаблонного метода для выполнения кода.
Пример с использованием TransactionTemplate:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
@Service
public class TemplateTransactionService {
@Autowired
private TransactionTemplate transactionTemplate;
public void executeInTransaction() {
transactionTemplate.execute(status -> {
try {
performDatabaseOperation1();
performDatabaseOperation2();
} catch (Exception ex) {
status.setRollbackOnly(); // Указание на откат транзакции
throw ex;
}
return null;
});
}
private void performDatabaseOperation1() {
// Логика операции 1
}
private void performDatabaseOperation2() {
// Логика операции 2
}
}
#Java #Training #Spring #ManualTransactionService
Когда использовать ручное управление транзакциями?
Тонкий контроль над транзакциями: Если нужно управлять транзакцией на уровне нескольких сервисов или разных контекстов.
Динамическое управление: Когда параметры транзакции (например, уровень изоляции) должны изменяться в зависимости от условий.
Исключение из стандартного поведения: Например, если нельзя использовать @Transactional из-за вызовов методов внутри одного класса.
#Java #Training #Spring #ManualTransactionService
Тонкий контроль над транзакциями: Если нужно управлять транзакцией на уровне нескольких сервисов или разных контекстов.
Динамическое управление: Когда параметры транзакции (например, уровень изоляции) должны изменяться в зависимости от условий.
Исключение из стандартного поведения: Например, если нельзя использовать @Transactional из-за вызовов методов внутри одного класса.
#Java #Training #Spring #ManualTransactionService
Rollback и Commit транзакций
Транзакции в приложениях обеспечивают выполнение группы операций над базой данных как единого целого. Два основных действия, которые завершают транзакцию, — это commit и rollback.
Что такое Commit?
Commit фиксирует все изменения, сделанные в рамках транзакции, и делает их видимыми для других транзакций. После выполнения команды commit изменения становятся постоянными и не могут быть отменены.
Пример в SQL:
Что такое Rollback?
Rollback отменяет все изменения, сделанные в рамках текущей транзакции, возвращая базу данных в состояние, предшествующее началу транзакции. Это полезно при возникновении ошибок, когда необходимо гарантировать, что никакие частично выполненные изменения не будут зафиксированы.
Пример в SQL:
Rollback и Commit в Spring
В Spring транзакции можно управлять как вручную, так и декларативно с помощью аннотации @Transactional.
Пример ручного управления:
#Java #Training #Spring #Rollback #Commit
Транзакции в приложениях обеспечивают выполнение группы операций над базой данных как единого целого. Два основных действия, которые завершают транзакцию, — это commit и rollback.
Что такое Commit?
Commit фиксирует все изменения, сделанные в рамках транзакции, и делает их видимыми для других транзакций. После выполнения команды commit изменения становятся постоянными и не могут быть отменены.
Пример в SQL:
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT;
В этом случае изменения будут сохранены в базе данных.
Что такое Rollback?
Rollback отменяет все изменения, сделанные в рамках текущей транзакции, возвращая базу данных в состояние, предшествующее началу транзакции. Это полезно при возникновении ошибок, когда необходимо гарантировать, что никакие частично выполненные изменения не будут зафиксированы.
Пример в SQL:
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
ROLLBACK;
В этом случае все изменения будут отменены.
Rollback и Commit в Spring
В Spring транзакции можно управлять как вручную, так и декларативно с помощью аннотации @Transactional.
Пример ручного управления:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class ManualTransactionService {
@Autowired
private PlatformTransactionManager transactionManager;
public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// Дебет с одного счета
debitAccount(fromAccountId, amount);
// Кредит на другой счет
creditAccount(toAccountId, amount);
// Подтверждение транзакции
transactionManager.commit(status);
} catch (Exception ex) {
// Откат транзакции в случае ошибки
transactionManager.rollback(status);
throw ex;
}
}
private void debitAccount(Long accountId, double amount) {
// Логика дебетовой операции
}
private void creditAccount(Long accountId, double amount) {
// Логика кредитной операции
}
}
#Java #Training #Spring #Rollback #Commit