Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Транзакции в Spring

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

Транзакция — это последовательность операций, которые выполняются как единое целое. Если хотя бы одна из операций в транзакции завершается с ошибкой, все изменения, сделанные в рамках этой транзакции, откатываются.

Ключевые свойства транзакций определяются через 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
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

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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
11%
35 5
44%
70 5
0%
35 10
44%
70 10
А потом Oracle и сделать из Pyton фраймворк Java😂😂😂

https://t.me/Java_for_beginner_dev

#Mems
Аннотация @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.


А в остальном всем теплых и светлых выходных!🫡
This media is not supported in your browser
VIEW IN TELEGRAM
Всем привет!🖐

Сегодня в 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
Оглавление для обучающих постов.

Если хотите найти информацию по Java, ранее опубликованную на канале - для Вас подготовлено оглавление уже из 3-х частей!

Пользуйтесь на здоровье!🫡

Часть 1.
Часть 2.
Часть 3. SPRING

Часть 2 дополнена.

Читайте, используйте, будут вопросы - пишите!😉
Простое Web приложение с асинхронной работой методов на Spring. Встреча от 24.11.2024

Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE

Спасибо всем кто пришел, за участие!💪

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

Кроме того в тесте к данному приложению рассмотрели различные варианты использования методов многопоточности.


Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!

Ссылка на GitHub - https://github.com/Oleborn/MultiThreadingSpringApp

Всем хорошего настроения! 🫡✌️
Уровни изоляции транзакций и виды проблем

Когда несколько транзакций работают одновременно, необходимо обеспечить согласованность данных. Для этого в реляционных базах данных применяются уровни изоляции. Они определяют, каким образом одна транзакция видит изменения, сделанные другой.

Уровни изоляции транзакций

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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
27%
zbbccwfyff
7%
xbbccwfyff
0%
xbbccdyff
67%
xbbccwyff
"Френдли" на максимум 🤪😂😂😂

https://t.me/Java_for_beginner_dev

#Mems
Управление транзакциями вручную

Хотя 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
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
Rollback с использованием @Transactional

В декларативном подходе Spring автоматически выполняет rollback для транзакций, если метод выбрасывает RuntimeException или Error.

Пример:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PaymentService {

@Transactional
public void processPayment(Long orderId) {
try {
// Обновление информации о заказе
updateOrder(orderId);

// Обновление платежной информации
updatePayment(orderId);
} catch (Exception e) {
// Логика обработки исключения
throw new RuntimeException("Ошибка при обработке платежа");
}
}

private void updateOrder(Long orderId) {
// Логика обновления заказа
}

private void updatePayment(Long orderId) {
// Логика обновления платежа
}
}
Если возникает RuntimeException, Spring автоматически откатывает транзакцию.


Принудительный rollback

Если требуется явно указать Spring, что транзакция должна быть откатана, можно использовать TransactionAspectSupport:

import org.springframework.transaction.interceptor.TransactionAspectSupport;

public void performOperation() {
try {
// Код операции
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}


#Java #Training #Spring #Rollback #Commit