Bu bo‘lim quyidagilarni qamrab oladi: Propagation levels, Isolation levels, Rollback rules, TransactionTemplate, va @Transactional proxy/self-call muammolari.
1. Transaction nima?
Transaction - bir nechta database operatsiyani bitta yaxlit ish sifatida bajarish mexanizmi.
Masalan pul o‘tkazish:
1. Ali hisobidan 100 000 so‘m ayirish
2. Vali hisobiga 100 000 so‘m qo‘shishBu ikkala amal ham bajarilishi kerak. Bittasi bajarilib, ikkinchisi xato bo‘lsa, sistema buziladi.
Shuning uchun transaction kerak:
Hammasi bajarildi -> COMMIT
Xato bo‘ldi -> ROLLBACK2. Transactionning asosiy maqsadi: ACID
Transaction odatda ACID prinsipiga tayanadi.
Prinsip | Ma’nosi |
|---|---|
Atomicity | Hammasi bajariladi yoki hech biri bajarilmaydi |
Consistency | Database noto‘g‘ri holatga tushib qolmaydi |
Isolation | Bir transaction boshqasiga noto‘g‘ri ta’sir qilmaydi |
Durability | Commit bo‘lgan data saqlanib qoladi |
Masalan:
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
accountRepository.decreaseBalance(fromId, amount);
accountRepository.increaseBalance(toId, amount);
}Agar increaseBalance() xato bersa, decreaseBalance() ham rollback bo‘ladi.
3. Spring’da transaction qanday ishlaydi?
Spring’da eng ko‘p ishlatiladigan usul:
@Transactional
public void createOrder() {
// DB operations
}Lekin ichkarida Spring taxminan shunday qiladi:
try {
transactionManager.begin();
createOrder();
transactionManager.commit();
} catch (Exception e) {
transactionManager.rollback();
throw e;
}Siz faqat annotation yozasiz. Spring esa transaction ochish, commit qilish, rollback qilishni boshqaradi.
4. @Transactional qayerga qo‘yiladi?
Eng yaxshi joy - service layer.
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentRepository paymentRepository;
public OrderService(
OrderRepository orderRepository,
PaymentRepository paymentRepository
) {
this.orderRepository = orderRepository;
this.paymentRepository = paymentRepository;
}
@Transactional
public void createOrder(CreateOrderRequest request) {
Order order = new Order();
orderRepository.save(order);
Payment payment = new Payment();
payment.setOrder(order);
paymentRepository.save(payment);
}
}Nega controllerga emas?
@RestController
public class OrderController {
@Transactional // yomon amaliyot
@PostMapping("/orders")
public void create() {
}
}Controller HTTP bilan ishlashi kerak. Transaction esa biznes operatsiya chegarasida bo‘lishi kerak.
To‘g‘ri chegara:
Controller -> Service transaction -> Repository5. @Transactional class level vs method level
Method level
@Service
public class UserService {
@Transactional
public void createUser() {
}
public User getUser() {
}
}Faqat createUser() transaction bilan ishlaydi.
Class level
@Service
@Transactional
public class UserService {
public void createUser() {
}
public void updateUser() {
}
public User getUser() {
}
}Bu classdagi public methodlarning hammasiga transaction qo‘llanadi.
Lekin o‘qish methodlari uchun alohida belgilash yaxshi:
@Transactional(readOnly = true)
public User getUser(Long id) {
return userRepository.findById(id).orElseThrow();
}6. readOnly = true nima qiladi?
@Transactional(readOnly = true)
public List<User> getUsers() {
return userRepository.findAll();
}Bu Spring va ORMga signal beradi:
"Bu transaction ichida data o‘zgarmaydi, faqat o‘qiladi."
Foydasi:
Hibernate dirty checkingni kamaytirishi mumkin;
ba’zi DB optimizatsiyalar ishlashi mumkin;
kod niyatini aniq ko‘rsatadi.
Lekin bu har doim "write qilishni fizik bloklaydi" degani emas. Ba’zi holatda DB yoki ORM baribir yozishga ruxsat berishi mumkin. Shuning uchun readOnly = trueni xavfsizlik mexanizmi deb emas, optimizatsiya va niyat belgisi deb tushunish kerak.
7. Rollback qoidalari
Spring’da default qoida:
Exception turi | Rollback bo‘ladimi? |
|---|---|
| Ha |
| Ha |
Checked exception | Yo‘q |
RuntimeException rollback qiladi
@Transactional
public void createOrder() {
orderRepository.save(new Order());
throw new RuntimeException("Something went wrong");
}Bu holatda save() rollback bo‘ladi.
Checked exception default rollback qilmaydi
@Transactional
public void createOrder() throws IOException {
orderRepository.save(new Order());
throw new IOException("File error");
}Bu holatda default bo‘yicha rollback bo‘lmasligi mumkin, chunki IOException - checked exception.
Rollback kerak bo‘lsa:
@Transactional(rollbackFor = IOException.class)
public void createOrder() throws IOException {
orderRepository.save(new Order());
throw new IOException("File error");
}8. rollbackFor va noRollbackFor
rollbackFor
@Transactional(rollbackFor = Exception.class)
public void importUsers() throws Exception {
userRepository.save(new User());
throw new Exception("Import failed");
}Bu checked exception uchun ham rollback qiladi.
noRollbackFor
Ba’zan exception bo‘lsa ham rollback qilmaslik kerak bo‘ladi.
@Transactional(noRollbackFor = NotificationException.class)
public void createOrder() {
orderRepository.save(new Order());
try {
notificationService.sendSms();
} catch (NotificationException e) {
throw e;
}
}Lekin bunday kodni ehtiyotkorlik bilan yozish kerak. Ko‘pincha notificationni transaction ichida qilmaslik yaxshiroq.
9. Eng katta xato: exceptionni yutib yuborish
Yomon:
@Transactional
public void createOrder() {
try {
orderRepository.save(new Order());
paymentRepository.save(new Payment());
} catch (Exception e) {
log.error("Error", e);
}
}Bu yerda exception tashqariga chiqmaydi. Spring transactionni muvaffaqiyatli deb o‘ylaydi va commit qiladi.
To‘g‘ri:
@Transactional
public void createOrder() {
try {
orderRepository.save(new Order());
paymentRepository.save(new Payment());
} catch (Exception e) {
log.error("Error", e);
throw e;
}
}Yoki custom exception:
@Transactional
public void createOrder() {
try {
orderRepository.save(new Order());
paymentRepository.save(new Payment());
} catch (Exception e) {
throw new OrderCreationException("Order creation failed", e);
}
}10. Propagation nima?
Propagation - agar bir transaction ichida boshqa transactionli method chaqirilsa, Spring nima qilishi kerakligini bildiradi.
Masalan:
@Transactional
public void createOrder() {
saveOrder();
saveAudit();
}Agar saveAudit() ham @Transactional bo‘lsa, u yangi transaction ochadimi yoki mavjudiga qo‘shiladimi?
Buni propagation belgilaydi.
11. Propagation.REQUIRED
Default propagation - REQUIRED.
@Transactional(propagation = Propagation.REQUIRED)
public void saveOrder() {
}Ma’nosi:
Agar transaction bor bo‘lsa -> unga qo‘shil
Agar transaction yo‘q bo‘lsa -> yangi ochBu eng ko‘p ishlatiladigan holat.
Misol:
@Service
public class OrderService {
@Transactional
public void createOrder() {
orderRepository.save(new Order());
auditService.saveAudit();
}
}@Service
public class AuditService {
@Transactional
public void saveAudit() {
auditRepository.save(new AuditLog());
}
}Bu yerda saveAudit() default REQUIRED, demak createOrder() transactioniga qo‘shiladi.
Agar createOrder() rollback bo‘lsa, audit ham rollback bo‘ladi.
12. Propagation.REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveAudit() {
}Ma’nosi:
Har doim yangi transaction och
Agar eski transaction bo‘lsa, vaqtincha to‘xtatReal misol: order xato bo‘lsa ham audit saqlansin.
@Service
public class OrderService {
@Transactional
public void createOrder() {
try {
orderRepository.save(new Order());
throw new RuntimeException("Order failed");
} catch (Exception e) {
auditService.saveAudit("ORDER_FAILED");
throw e;
}
}
}@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveAudit(String message) {
auditRepository.save(new AuditLog(message));
}
}Natija:
Order -> rollback
Audit -> commitBu productionda juda foydali.
Lekin haddan tashqari ishlatilsa:
connection pool bosimi oshadi;
transaction oqimi murakkablashadi;
debugging qiyinlashadi.
13. Propagation.NESTED
@Transactional(propagation = Propagation.NESTED)
public void saveChildData() {
}Ma’nosi:
Mavjud transaction ichida savepoint yaratadi
Ichki qism rollback bo‘lsa, butun transaction emas, shu qism rollback bo‘lishi mumkinTasavvur:
Outer transaction start
save order
savepoint
save optional details
error
rollback to savepoint
continue outer transaction
commit outer transactionMisol:
@Transactional
public void createOrder() {
orderRepository.save(new Order());
try {
optionalService.saveOptionalDetails();
} catch (Exception e) {
log.warn("Optional details failed");
}
}@Transactional(propagation = Propagation.NESTED)
public void saveOptionalDetails() {
optionalRepository.save(new OptionalDetails());
throw new RuntimeException("Optional failed");
}NESTED hamma transaction managerlarda bir xil ishlamasligi mumkin. Odatda JDBC savepoint qo‘llab-quvvatlashi kerak.
14. Boshqa propagation turlari
Propagation | Ma’nosi |
|---|---|
| Bor transactionga qo‘shiladi, bo‘lmasa yangi ochadi |
| Har doim yangi transaction ochadi |
| Existing transaction ichida savepoint ishlatadi |
| Transaction bo‘lsa ishlatadi, bo‘lmasa transactionsiz ishlaydi |
| Transactionsiz ishlaydi, bor transactionni suspend qiladi |
| Transaction bo‘lishi shart, bo‘lmasa xato |
| Transaction bo‘lmasligi kerak, bo‘lsa xato |
Eng ko‘p ishlatiladi:
REQUIRED
REQUIRES_NEW
NESTED15. Isolation nima?
Isolation - parallel transactionlar bir-birini qanday ko‘rishini belgilaydi.
Bir vaqtning o‘zida ikkita request keldi:
Transaction A: user balansini o‘qiyapti
Transaction B: shu balansni o‘zgartiryaptiSavol:
A transaction B hali commit qilmagan datani ko‘rishi mumkinmi?
Buni isolation level hal qiladi.
16. Isolation muammolari
16.1 Dirty Read
Bir transaction boshqa transactionning hali commit qilinmagan datasini o‘qiydi.
Transaction B: balance = 100 dan 50 qildi, lekin commit qilmadi
Transaction A: balance = 50 deb o‘qidi
Transaction B: rollback qildiA noto‘g‘ri data o‘qidi.
16.2 Non-repeatable Read
Bir transaction bir xil rowni ikki marta o‘qiydi, lekin natija o‘zgarib qoladi.
Transaction A: balance = 100 o‘qidi
Transaction B: balance = 200 qilib commit qildi
Transaction A: yana o‘qidi -> balance = 200Bitta transaction ichida bir xil row har xil chiqdi.
16.3 Phantom Read
Bir transaction bir xil queryni ikki marta ishlatadi, lekin ikkinchi safar yangi rowlar paydo bo‘ladi.
Transaction A: SELECT * FROM orders WHERE status = 'NEW' -> 10 ta
Transaction B: yangi NEW order qo‘shdi, commit qildi
Transaction A: yana query qildi -> 11 ta17. Isolation levellar
Isolation | Dirty Read | Non-repeatable Read | Phantom Read |
|---|---|---|---|
| Mumkin | Mumkin | Mumkin |
| Yo‘q | Mumkin | Mumkin |
| Yo‘q | Yo‘q | DBga bog‘liq |
| Yo‘q | Yo‘q | Yo‘q |
18. READ_COMMITTED
@Transactional(isolation = Isolation.READ_COMMITTED)
public void process() {
}Ma’nosi:
Faqat commit qilingan datani o‘qiydi.
Ko‘p database’larda default darajaga yaqin. Masalan, PostgreSQL default isolation - READ COMMITTED.
Bu odatda ko‘p business applicationlar uchun yetarli.
19. REPEATABLE_READ
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void process() {
}Ma’nosi:
Bitta transaction ichida o‘qilgan row qayta o‘qilganda o‘zgarmas bo‘lib ko‘rinadi.
Bu inventory, balance, stock kabi joylarda foydali bo‘lishi mumkin.
Lekin har doim ham race conditionni to‘liq hal qilmaydi. Ba’zan explicit lock yoki optimistic locking kerak bo‘ladi.
20. SERIALIZABLE
@Transactional(isolation = Isolation.SERIALIZABLE)
public void process() {
}Eng kuchli isolation.
Ma’nosi:
Transactionlar xuddi ketma-ket bajarilgandek natija beradi.
Kamchiligi:
sekinroq;
locklar ko‘payadi;
deadlock ehtimoli oshadi;
throughput pasayadi.
Shuning uchun uni default qilib qo‘yish noto‘g‘ri.
21. Real muammo: lost update
Ikki user bir vaqtda bitta mahsulot stockini kamaytiryapti.
Initial stock = 10
Transaction A: stock = 10 o‘qidi
Transaction B: stock = 10 o‘qidi
A: stock = 9 saqladi
B: stock = 9 saqladiAslida stock 8 bo‘lishi kerak edi, lekin 9 bo‘lib qoldi.
Bu lost update.
Yechimlar:
optimistic locking;
pessimistic locking;
atomic update query;
yuqoriroq isolation;
business constraintlar.
22. Optimistic locking
Entityga version qo‘shiladi:
@Entity
public class Product {
@Id
private Long id;
private int stock;
@Version
private Long version;
}Agar ikki transaction bitta rowni update qilsa, bittasi muvaffaqiyatli bo‘ladi, ikkinchisi OptimisticLockException oladi.
Bu high-read, low-conflict systemlarda yaxshi.
23. Pessimistic locking
Rowni lock qilib qo‘yish.
public interface ProductRepository extends JpaRepository<Product, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select p from Product p where p.id = :id")
Optional<Product> findByIdForUpdate(Long id);
}Service:
@Transactional
public void decreaseStock(Long productId) {
Product product = productRepository.findByIdForUpdate(productId)
.orElseThrow();
product.decreaseStock();
}Bu holatda boshqa transaction shu rowni yozish uchun kutadi.
Kamchiligi:
lock kutish;
deadlock;
throughput pasayishi.
24. Atomic update query
Ko‘p holatda eng sodda va kuchli yechim:
@Modifying
@Query("""
update Product p
set p.stock = p.stock - :amount
where p.id = :id and p.stock >= :amount
""")
int decreaseStock(Long id, int amount);Service:
@Transactional
public void buy(Long productId, int amount) {
int updated = productRepository.decreaseStock(productId, amount);
if (updated == 0) {
throw new IllegalStateException("Not enough stock");
}
}Bu read -> modify -> write muammosini kamaytiradi.
25. Transaction va flush
JPA/Hibernate’da save() chaqirilganda SQL darrov DBga ketmasligi mumkin.
@Transactional
public void createUser() {
userRepository.save(new User("Ali"));
System.out.println("Saved");
}Hibernate SQLni odatda:
flush paytida;
querydan oldin;
transaction commit oldidan;
yuboradi.
Majburiy flush:
userRepository.saveAndFlush(user);Yoki:
entityManager.flush();Lekin flush() commit degani emas. Flush SQLni DBga yuboradi, transaction hali rollback bo‘lishi mumkin.
26. Transaction va Lazy loading
@Transactional(readOnly = true)
public Order getOrder(Long id) {
Order order = orderRepository.findById(id).orElseThrow();
order.getItems().size();
return order;
}items LAZY bo‘lsa, transaction ochiq paytda yuklanadi.
Lekin transactiondan tashqarida:
Order order = orderService.getOrder(id);
order.getItems().size(); // LazyInitializationExceptionBu muammo chiqishi mumkin.
Yechimlar:
DTOga map qilish transaction ichida;
fetch join;
entity graph;
queryni to‘g‘ri yozish;
Open Session in View’ga suyanmaslik.
27. @Transactional va self-invocation
Bu juda muhim.
@Service
public class UserService {
public void register() {
saveUser();
}
@Transactional
public void saveUser() {
userRepository.save(new User());
}
}Bu yerda register() ichidan saveUser() chaqirilsa, transaction ishlamasligi mumkin.
Sabab:
this.saveUser()proxy orqali o‘tmaydi.
Tashqaridan chaqirilsa:
Controller -> UserService Proxy -> saveUser()ishlaydi.
Ichkaridan chaqirilsa:
UserService object -> this.saveUser()proxy chetlab o‘tiladi.
28. Self-invocation yechimi
Eng toza yechim - methodlarni boshqa servicega ajratish.
@Service
public class UserRegistrationService {
private final UserPersistenceService userPersistenceService;
public UserRegistrationService(UserPersistenceService userPersistenceService) {
this.userPersistenceService = userPersistenceService;
}
public void register() {
userPersistenceService.saveUser();
}
}@Service
public class UserPersistenceService {
@Transactional
public void saveUser() {
userRepository.save(new User());
}
}Bu yerda chaqiruv proxy orqali o‘tadi.
29. Private methodda @Transactional
Ishlamaydi.
@Transactional
private void saveUser() {
}Spring AOP proxy private methodni intercept qila olmaydi.
Odatda transaction methodlari public bo‘lishi kerak.
30. Final method/class muammosi
CGLIB proxy final methodni override qila olmaydi.
Yomon:
@Service
public final class PaymentService {
@Transactional
public void pay() {
}
}Yoki:
@Service
public class PaymentService {
@Transactional
public final void pay() {
}
}Bunday holatlarda transaction ishlamasligi yoki kutilmagan muammo berishi mumkin.
31. Multiple transaction manager
Ba’zan projectda bir nechta database bo‘ladi.
@Transactional(transactionManager = "orderTransactionManager")
public void createOrder() {
}Yoki:
@Transactional(transactionManager = "paymentTransactionManager")
public void createPayment() {
}Agar noto‘g‘ri transaction manager tanlansa, transaction kutganingizdek ishlamaydi.
Distributed transaction esa alohida murakkab mavzu. Ko‘p microservice architecture’da 2PC o‘rniga:
Saga;
transactional outbox;
idempotency;
event-driven consistency;
ishlatiladi.
32. Programmatic transaction: TransactionTemplate
Ba’zan annotation yetarli bo‘lmaydi. Transaction chegarasini kod ichida aniq boshqarish kerak bo‘ladi.
@Service
public class OrderService {
private final TransactionTemplate transactionTemplate;
public OrderService(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void createOrder() {
transactionTemplate.execute(status -> {
orderRepository.save(new Order());
paymentRepository.save(new Payment());
return null;
});
}
}Bu programmatic transaction deyiladi.
33. TransactionTemplate qachon kerak?
Masalan, bitta method ichida:
1. DB transactionda order yaratish
2. Transactiondan tashqarida external API chaqirish
3. Yana alohida transactionda audit yozishAnnotation bilan bu ko‘pincha noqulay.
public void processOrder() {
Long orderId = transactionTemplate.execute(status -> {
Order order = orderRepository.save(new Order());
return order.getId();
});
externalPaymentClient.charge(orderId);
transactionTemplate.execute(status -> {
auditRepository.save(new AuditLog("PAYMENT_CHARGED"));
return null;
});
}Bu yerda transaction chegaralari aniq ko‘rinib turibdi.
34. Transaction ichida external API chaqirish xatosi
Yomon:
@Transactional
public void createOrder() {
orderRepository.save(new Order());
paymentClient.charge(); // external API
orderRepository.updateStatus();
}Nega yomon?
DB connection uzoq vaqt band bo‘ladi;
external API sekin bo‘lsa transaction cho‘ziladi;
timeout bo‘lishi mumkin;
locklar uzoq ushlanadi;
rollback external API’ni ortga qaytara olmaydi.
Yaxshiroq yondashuv:
1. Order CREATED holatda saqlanadi
2. Payment event yuboriladi
3. Payment natijasiga qarab status update bo‘ladiYoki transactional outbox pattern.
35. Transactional outbox qisqacha
Muammo:
DBga order saqlandi
Kafka/RabbitMQga event yuborish kerakAgar DB commit bo‘ldi, lekin event yuborilmadi - data mismatch.
Outbox yechim:
Bitta DB transaction ichida:
1. Order save
2. Outbox event save
Keyin alohida worker:
1. Outbox eventlarni o‘qiydi
2. Kafka/RabbitMQga yuboradi
3. sent deb belgilaydiService:
@Transactional
public void createOrder() {
Order order = orderRepository.save(new Order());
outboxRepository.save(new OutboxEvent(
"ORDER_CREATED",
order.getId()
));
}Bu microservice architecture’da juda kerakli pattern.
36. @Transactional va async
Ehtiyot bo‘lish kerak:
@Transactional
public void createOrder() {
orderRepository.save(new Order());
asyncService.sendNotification();
}@Async
public void sendNotification() {
}@Async boshqa threadda ishlaydi. Transaction context avtomatik ravishda boshqa threadga o‘tmaydi.
Shuning uchun async method ichida lazy entity, transaction context yoki sessionga suyanish xato.
Yaxshi yondashuv:
@Transactional
public void createOrder() {
Order order = orderRepository.save(new Order());
eventPublisher.publishEvent(new OrderCreatedEvent(order.getId()));
}Keyin transaction commit bo‘lgandan keyin event ishlatish:
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(OrderCreatedEvent event) {
notificationService.send(event.orderId());
}37. @TransactionalEventListener
Bu juda foydali.
@Transactional
public void createOrder() {
Order order = orderRepository.save(new Order());
applicationEventPublisher.publishEvent(
new OrderCreatedEvent(order.getId())
);
}Listener:
@Component
public class OrderEventListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void afterCommit(OrderCreatedEvent event) {
notificationService.sendOrderCreated(event.orderId());
}
}Bu listener faqat transaction commit bo‘lgandan keyin ishlaydi.
Fazalar:
Phase | Qachon ishlaydi? |
|---|---|
| Commitdan oldin |
| Commitdan keyin |
| Rollbackdan keyin |
| Commit yoki rollbackdan keyin |
38. Transaction timeout
@Transactional(timeout = 5)
public void process() {
// 5 sekunddan oshmasligi kerak
}Agar transaction juda cho‘zilib ketsa, timeout bo‘lishi mumkin.
Bu ayniqsa:
batch processing;
external dependency;
lock kutish;
katta querylar;
uchun muhim.
39. Transaction ichida nima qilmaslik kerak?
Transaction ichida quyidagilarni minimal qiling:
Qilmaslik kerak | Sabab |
|---|---|
External API call | Sekin, rollback qilib bo‘lmaydi |
File upload/download | DB connection band bo‘ladi |
Email/SMS yuborish | Commit bo‘lmasdan xabar ketib qolishi mumkin |
Katta loop ichida ko‘p save | Batch kerak |
User input kutish | Transaction juda cho‘ziladi |
Keraksiz querylar | Lock va connection bosimi oshadi |
40. Best practice
1. Transactionni service layerda saqlang
Controller -> Service @Transactional -> Repository2. Transactionni qisqa tuting
Faqat DB consistency uchun kerakli kod transaction ichida bo‘lsin.
3. External API’ni transaction tashqarisiga chiqaring
Ayniqsa payment, SMS, email, file storage.
4. Exceptionni yutmang
Rollback kerak bo‘lsa exception tashqariga chiqsin.
5. readOnly = true ishlating
Read-only query methodlarda niyatni aniq ko‘rsating.
6. Self-invocationdan ehtiyot bo‘ling
this.method() transactionni chetlab o‘tishi mumkin.
7. Propagationni tushunmasdan o‘zgartirmang
REQUIRES_NEW kuchli, lekin noto‘g‘ri ishlatilsa muammo ko‘paytiradi.
8. Isolationni defaultdan oshirishdan oldin o‘ylang
Ko‘pincha muammo isolation bilan emas, locking/modeling bilan hal qilinadi.
41. Interview savollar
Savol 1: @Transactional qanday ishlaydi?
Javob:
Spring
@Transactionalmethod atrofida proxy yaratadi. Method chaqirilganda proxy transaction ochadi, method muvaffaqiyatli tugasa commit qiladi, runtime exception bo‘lsa rollback qiladi.
Savol 2: Checked exception rollback qiladimi?
Javob:
Default holatda yo‘q. Spring runtime exception va errorlarda rollback qiladi. Checked exception uchun
rollbackForberish kerak.
@Transactional(rollbackFor = IOException.class)Savol 3: REQUIRED va REQUIRES_NEW farqi nima?
Javob:
REQUIREDmavjud transactionga qo‘shiladi, yo‘q bo‘lsa yangi ochadi.REQUIRES_NEWesa har doim yangi transaction ochadi va mavjud transactionni vaqtincha suspend qiladi.
Savol 4: Isolation level nima?
Javob:
Isolation parallel transactionlar bir-birining o‘zgarishlarini qanday ko‘rishini belgilaydi. Masalan dirty read, non-repeatable read, phantom read kabi muammolarni boshqaradi.
Savol 5: Nega transaction ichida external API chaqirish yomon?
Javob:
Chunki transaction uzoq ochiq qoladi, DB connection va locklar band bo‘ladi. External API sekin yoki xato bo‘lishi mumkin. Bundan tashqari DB rollback bo‘lsa ham external API chaqiruvini rollback qilib bo‘lmaydi.
Savol 6: Self-invocation transactionga qanday ta’sir qiladi?
Javob:
Agar
@Transactionalmethod shu class ichidanthis.method()orqali chaqirilsa, chaqiruv Spring proxy orqali o‘tmaydi. Shuning uchun transaction ishlamasligi mumkin.
42. Qisqa xulosa
Transaction management - faqat @Transactional qo‘yish emas.
Developer quyidagilarni tushunishi kerak:
Mavzu | Muhim xulosa |
|---|---|
| Proxy orqali ishlaydi |
Rollback | Runtime exception rollback qiladi, checked exception default rollback qilmaydi |
Propagation | Ichma-ich transactionlar qanday ishlashini belgilaydi |
Isolation | Parallel transaction muammolarini boshqaradi |
Locking | Lost update kabi muammolar uchun kerak |
TransactionTemplate | Transaction chegarasini kod bilan boshqaradi |
External API | Transaction ichida chaqirish xavfli |
Self-invocation | Proxy chetlab o‘tilsa transaction ishlamaydi |
Eng muhim gap:
Transaction qisqa, aniq va service layer darajasida bo‘lishi kerak. Transaction ichida faqat database consistency uchun zarur ishlar bajarilishi kerak.