MS Lesson15: Transaction propogation

1. A servisi transactional metodu var ve B servisindeki non transactional metodu cagiri:

package guru.springframework.cruddemo.controller;

import guru.springframework.cruddemo.service.impl.AccountServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
@RequiredArgsConstructor
public class AccountController {

private final AccountServiceImpl accountServiceImpl;

@PostMapping("/transfer")
public void transfer() {
accountServiceImpl.transfer(30);
}

}


package guru.springframework.cruddemo.service.impl;

import guru.springframework.cruddemo.entity.Account;
import guru.springframework.cruddemo.repository.AccountRepository;
import guru.springframework.cruddemo.service.AccountService;
import guru.springframework.cruddemo.service.TxProxyDemoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@RequiredArgsConstructor
public class AccountServiceImpl implements AccountService {

private final AccountRepository accountRepository;
private final TxProxyDemoService txProxyDemoService;

@Override
@Transactional(propagation = Propagation.REQUIRED)
public void transfer(Integer amount) {
System.out.println(Thread.currentThread().getName());
Account fromAccount = accountRepository.findById(1L).get();
Account toAccount = accountRepository.findById(2L).get();
fromAccount.setAmount(fromAccount.getAmount() - amount);
toAccount.setAmount(toAccount.getAmount() + amount);
txProxyDemoService.test();
}

private void foo() {
throw new RuntimeException("---------> xeta");
}

}


package guru.springframework.cruddemo.service.impl;

import guru.springframework.cruddemo.entity.TxProxyDemo;
import guru.springframework.cruddemo.repository.TxProxyDemoRepository;
import guru.springframework.cruddemo.service.TxProxyDemoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class TxProxyDemoServiceImpl implements TxProxyDemoService {

private final TxProxyDemoRepository repository;

@Override
// @Transactional
public void test() {
System.out.println(Thread.currentThread().getName());
TxProxyDemo txProxyDemo = repository.findById(1L).get();
txProxyDemo.setContent("demo");
foo();
}

private void foo() {
throw new RuntimeException("------> Something went wrong");
}

}


Bu zaman transaction B servisindeki metoda da oturulur,  orada davam edir ve tranzaksiya A servisindeki metodda bitir.


2. Required - bu @Transactional yazanda default secimdir.

A servisindeki @Transactional metoddan B servisindeki @Transactional metodu cagirirsa B servisindeki tranzaksiya yeni tranzaksiya acmir A ni davam eletdirir, yeni A nin tranzaksiyasi B ye oturulur. 

Bu zaman her hansisa bir metodda Runtime exception bash verersen bu tranzaksiya vahid bir tranzaksiya kimi davranacaq ve butun emeliyyat (hem A hem B) rollback olacaq.



3. Requires_new - bu zaman yeni tranzaksiya serhedi teyin olunur. Bunu gormek ucun:

System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());

Qisa qayda: Requires_new neye gore var? Birincide xeta bash verse ikinciye tesir etmesin, bu qeder sade.


4. Supports - tranzaksiya varsa qatil, yoxdursa tranzaksiyasiz ishle.

Qisa qayda: yazsanda yazmasanda ferq etmir.


5. Not_supported - tranzaksiya varsa suspend et, tranzaksiya olmadan ishle. 

package guru.springframework.cruddemo.service.impl;

import guru.springframework.cruddemo.entity.Account;
import guru.springframework.cruddemo.repository.AccountRepository;
import guru.springframework.cruddemo.service.AccountService;
import guru.springframework.cruddemo.service.TxProxyDemoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Service
@Slf4j
@RequiredArgsConstructor
public class AccountServiceImpl implements AccountService {

private final AccountRepository accountRepository;
private final TxProxyDemoService txProxyDemoService;

@Override
@Transactional(propagation = Propagation.REQUIRED)
public void transfer(Integer amount) {
System.out.println(Thread.currentThread().getName());
System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
Account fromAccount = accountRepository.findById(1L).get();
Account toAccount = accountRepository.findById(2L).get();
fromAccount.setAmount(fromAccount.getAmount() - amount);
toAccount.setAmount(toAccount.getAmount() + amount);
txProxyDemoService.test();
// foo();
}

private void foo() {
throw new RuntimeException("---------> xeta");
}

}


package guru.springframework.cruddemo.service.impl;

import guru.springframework.cruddemo.entity.TxProxyDemo;
import guru.springframework.cruddemo.repository.TxProxyDemoRepository;
import guru.springframework.cruddemo.service.TxProxyDemoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Slf4j
@Service
@RequiredArgsConstructor
public class TxProxyDemoServiceImpl implements TxProxyDemoService {

private final TxProxyDemoRepository repository;

@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void test() {
System.out.println(Thread.currentThread().getName());
System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
TxProxyDemo txProxyDemo = repository.findById(1L).get();
txProxyDemo.setContent("demo");
// repository.save(txProxyDemo);
// foo();
}

private void foo() {
throw new RuntimeException("------> Something went wrong");
}

}


test() metodunda RuntimeException bash verse bu exceptionu cagirildigi metode yoneldecek.

Ne zaman lazim ola biler: cox vaxt uzun ve ya yavash ishleyen ishler (mes. email, HTTP fayl, agir hesabat) ve ya bu addim aktiv DB transaction-da olmasin dediyimiz hallarda - esas transaction-u suspend edib hemin hisseni tx-siz ishletmek ucun.


6. Mandatory - mutleq aktiv tranzaksiya olmalidir, eks halda xeta atilacaq. open-in-view = true buna hec bir tesiri yoxdur, yalniz session aciq saxlayir, response controllere qayitdiqdan sonra session baglanir. 


7. Never - hec vaxt tranzaksiya olmamalidir, varsa xeta atsin. Tranzaksiya yoxdursa normal tranzaksiyasiz (adi metod kimi) ishleyir. 


8. Nested - daxili nested savepoint (JDBC savepoint; DataSource desteklemelidir). Spring-in yeni versiyasinda desteklemir, evezine : Required_new + try/catch bloku. Yeni B-de xeta olsa bele, A davam etsin.





























Комментарии