Spring Framework dasturiy boshqarish transaksiyalarini bajarish uchun ikki usul taklif qiladi:
-
TransactionTemplateyokiTransactionalOperator. -
Bevosita
TransactionManagerni amalga oshirish.
Spring jamoasi odatda dasturiy boshqarish transaksiyalari uchun TransactionTemplate dan foydalanishni tavsiya qiladi va reaktiv kod uchun TransactionalOperator. Ikkinchi yondashuv JTA dan UserTransaction API-ni ishlatishga o`xshaydi, ammo istisnolarni ishlash kamroq yuklangan.
TransactionTemplate dan foydalanish
TransactionTemplate shabloni boshqa Spring shablonlari kabi bir xil yondashuvni qo'llaydi, masalan, JdbcTemplate. U qayta chaqirish yondashuvini qo'llaydi (dasturiy kodni transaksion resurslarni qo'lga kiritish va bo'shatish zaruratidan ozod qilish uchun) va bu niyat bilan boshqariladigan kod yaratishni talab qiladi, ya'ni sizning kodingiz ishlashingiz faqat bajarilishi kerak bo'lgan narsaga qaratilgan.
TransactionTemplate dan foydalanish to'liq sizni Spring ning transaksiyalar infratuzilmasi va API-siga bog'laydi. Dasturiy boshqarish transaksiyalari rivojlanishingiz uchun mos keladimi, buni siz o'zingiz hal qilishingiz kerak.
Dasturiy kod, transaksion kontekstda bajarilishi kerak va TransactionTemplate dan aniq foydalanadi, quyidagi misoldagi kabi ko'rinadi. Siz, dasturchi sifatida, transaksion kontekstda bajarilishi kerak bo'lgan kodni o'z ichiga olgan TransactionCallback ni amalga oshirishingiz mumkin (odatda anonim ichki sinf sifatida ifodalangan). So'ngra siz o'z moslashtirilgan TransactionCallback ni TransactionTemplate uchun ochiq bo'lgan execute(..) metodiga o'tkazasiz. Quyidagi misolda bu qanday qilish kerakligi ko'rsatilgan:
public class SimpleService implements Service {
// ushbu instansiya uchun barcha metodlar uchun umumiy TransactionTemplate
private final TransactionTemplate transactionTemplate;
// PlatformTransactionManager ni taqdim qilish uchun konstruktor orqali dependency injection dan foydalanamiz
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// bu metoddagi kod transaksion kontekstda bajariladi
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
// PlatformTransactionManager ni taqdim qilish uchun konstruktor orqali dependency injection dan foydalanamiz
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
// ushbu instansiya uchun barcha metodlar uchun umumiy TransactionTemplate
private val transactionTemplate = TransactionTemplate(transactionManager)
fun someServiceMethod() = transactionTemplate.execute<Any?> {
updateOperation1()
resultOfUpdateOperation2()
}
}
Agar qaytariladigan qiymat bo'lmasa, quyidagi misolda ko'rsatilganidek, anonim sinf bilan TransactionCallbackWithoutResult yordamchi sinfidan foydalanishingiz mumkin:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
override fun doInTransactionWithoutResult(status: TransactionStatus) {
updateOperation1()
updateOperation2()
}
})
Qayta chaqirish ichidagi kod, quyidagi misolda ko'rsatilganidek, berilgan TransactionStatus ob'ekti uchun setRollbackOnly() metodini chaqirib transaksiyani qaytarishi mumkin:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly(); // Faqat rollback
}
}
});
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
override fun doInTransactionWithoutResult(status: TransactionStatus) {
try {
updateOperation1()
updateOperation2()
} catch (ex: SomeBusinessException) {
status.setRollbackOnly()
}
}
})
Transaksiya parametrlarini o'rnatish
Transaksiya parametrlari (masalan, tarqalish rejimi, izolyatsiya darajasi, vaqt chegarasi va hokazo) TransactionTemplate shabloni uchun dasturiy yoki konfiguratsiyada o'rnatilishi mumkin. Default holatda TransactionTemplate instansiyalari standart transaksiyalar konfiguratsiyasiga ega. Quyidagi misolda ma'lum bir TransactionTemplate uchun transaksiyalar parametrlarini dasturiy ravishda sozlash ko'rsatilgan:
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
// zarur bo'lsa, bu yerda transaksiyalar parametrlarini aniq o'rnatishingiz mumkin
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 soniya
// va hokazo...
}
}
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
private val transactionTemplate = TransactionTemplate(transactionManager).apply {
// zarur bo'lsa, bu yerda transaksiyalar parametrlarini aniq o'rnatishingiz mumkin
isolationLevel = TransactionDefinition.ISOLATION_READ_UNCOMMITTED
timeout = 30 // 30 soniya
// va hokazo...
}
}
Quyidagi misolda TransactionTemplate ba'zi moslashtirilgan transaksiyalar sozlamalari bilan Spring'da XML-konfiguratsiya yordamida belgilangan:
<bean id="sharedTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>
So'ngra sharedTransactionTemplate ni zarur bo'lgan ko'p miqdordagi xizmatlarga kiritish mumkin.
Nihoyat, TransactionTemplate sinfining instansiyalari thread-safe hisoblanadi, chunki instansiyalar hech qanday muloqot holatini saqlamaydi. Biroq TransactionTemplate instansiyalari konfiguratsion holatni saqlaydi. Shu sababli, bir nechta sinflar bir TransactionTemplate instansiyasidan birgalikda foydalanishi mumkin, agar sinf TransactionTemplate dan turli parametrlar (masalan, turli izolyatsiya darajasi) bilan foydalanishi kerak bo'lsa, ikkita turli TransactionTemplate instansiyasini yaratish kerak.
TransactionalOperator dan foydalanish
TransactionalOperator dasturiy operator tuzilmasiga amal qiladi, bu boshqa reaktiv operatorlar bilan o'xshash. U qayta chaqirish yondashuvini qo'llaydi (dasturiy kodni transaksion resurslarni qo'lga kiritish va bo'shatish zaruratidan ozod qilish uchun) va bu niyat bilan boshqariladigan kod yaratishni talab qiladi, ya'ni sizning kodingiz ishlashingiz faqat bajarilishi kerak bo'lgan narsaga qaratilgan.
TransactionalOperator dan foydalanish to'liq sizni Spring ning transaksiyalar infratuzilmasi va API-siga bog'laydi. Dasturiy boshqarish transaksiyalari rivojlanishingiz uchun mos keladimi, buni siz o'zingiz hal qilishingiz kerak.
Dasturiy kod, transaksion kontekstda bajarilishi kerak va TransactionalOperator dan aniq foydalanadi, quyidagi misoldagi kabi ko'rinadi:
public class SimpleService implements Service {
// ushbu instansiya uchun barcha metodlar uchun umumiy TransactionalOperator
private final TransactionalOperator transactionalOperator;
// ReactiveTransactionManager ni taqdim qilish uchun konstruktor orqali dependency injection dan foydalanamiz
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionalOperator = TransactionalOperator.create(transactionManager);
}
public Mono<Object> someServiceMethod() {
// bu metoddagi kod transaksion kontekstda bajariladi
Mono<Object> update = updateOperation1();
return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
}
}
// ReactiveTransactionManager ni taqdim qilish uchun konstruktor orqali dependency injection dan foydalanamiz
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
// ushbu instansiya uchun barcha metodlar uchun umumiy TransactionalOperator
private val transactionalOperator = TransactionalOperator.create(transactionManager)
suspend fun someServiceMethod() = transactionalOperator.executeAndAwait<Any?> {
updateOperation1()
resultOfUpdateOperation2()
}
}
TransactionalOperator ikki usulda ishlatilishi mumkin:
-
Project Reactor dan turlar ishlatadigan operator asosida
(mono.as(transactionalOperator::transactional)) -
Boshqa hollarda qayta chaqirish asosida (
transactionalOperator.execute(TransactionCallback<T>))
Qayta chaqirish ichidagi kod, quyidagi misolda ko'rsatilganidek, berilgan ReactiveTransaction ob'ekti uchun setRollbackOnly() metodini chaqirib transaksiyani qaytarishi mumkin:
transactionalOperator.execute(new TransactionCallback<>() {
public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
transactionalOperator.execute(object : TransactionCallback() {
override fun doInTransactionWithoutResult(status: ReactiveTransaction) {
updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly())
}
})
Bekor qilish signallari
Reactive Streams da Subscriber o'zining Subscription ni bekor qilishi va Publisher ni to'xtatishi mumkin. Project Reactor da operatorlar, shuningdek boshqa kutubxonalar, masalan, next(), take(long), timeout(Duration) va boshqalar, bekor qilishi mumkin. Bekor qilish sababi, xato yoki shunchaki keyingi iste'molni qiziqmasligi haqida bilish mumkin emas. 5.3 versiyasidan boshlab bekor qilish signallari rollback qilishga sabab bo'ladi. Natijada tranzaksiyalar Publisher ni pastdan foydalanilgan operatorlarni ko'rib chiqish muhim. Xususan, Flux yoki boshqa ko'p miqdorli Publisher holatida tranzaksiyani yakunlash uchun to'liq natija iste'mol qilinishi kerak.
Transaksiyalar parametrlarini o'rnatish
Transaksiyalar parametrlarini (masalan, tarqalish rejimi, izolyatsiya darajasi, vaqt chegarasi va hokazo) TransactionalOperator uchun belgilashingiz mumkin. Default holatda TransactionalOperator instansiyalari standart transaksiya parametrlariga ega. Quyidagi misolda alohida TransactionalOperator uchun transaksiyalar parametrlarini sozlash ko'rsatilgan:
public class SimpleService implements Service {
private final TransactionalOperator transactionalOperator;
public SimpleService(ReactiveTransactionManager transactionManager) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// zarur bo'lsa, bu yerda transaksiyalar parametrlarini aniq o'rnatishingiz mumkin
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
definition.setTimeout(30); // 30 soniya
// va hokazo...
this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
}
}
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
private val definition = DefaultTransactionDefinition().apply {
// zarur bo'lsa, bu yerda transaksiyalar parametrlarini aniq o'rnatishingiz mumkin
isolationLevel = TransactionDefinition.ISOLATION_READ_UNCOMMITTED
timeout = 30 // 30 soniya
// va hokazo...
}
private val transactionalOperator = TransactionalOperator(transactionManager, definition)
}
TransactionManager dan foydalanish
Quyidagi bo'limlarda imperativ va reaktiv transaksiyalarni dasturiy boshqarish haqida aytiladi.
PlatformTransactionManager dan foydalanish
Imperativ transaksiyalar uchun org.springframework.transaction.PlatformTransactionManager ni to'g'ridan-to'g'ri ishlatish orqali transaksiyani boshqarishingiz mumkin. Buning uchun PlatformTransactionManager ni belgilaydigan amalga oshirilishini bean orqali bering. Keyin, TransactionDefinition va TransactionStatus ob'ektlaridan foydalanib, transaksiyalarni boshlash, rollback va commit qilish mumkin. Quyidagi misolda bu qanday qilish kerakligi ko'rsatilgan:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// Transaksiya nomini aniq belgilash dasturiy ravishda amalga oshiriladi
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// bu yerda biznes mantiqingizni joylashtiring
} catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
val def = DefaultTransactionDefinition()
// Transaksiya nomini aniq belgilash dasturiy ravishda amalga oshiriladi
def.setName("SomeTxName")
def.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
val status = txManager.getTransaction(def)
try {
// bu yerda biznes mantiqingizni joylashtiring
} catch (ex: MyException) {
txManager.rollback(status)
throw ex
}
txManager.commit(status)
ReactiveTransactionManager dan foydalanish
Reaktiv transaksiyalar bilan ishlaganda org.springframework.transaction.ReactiveTransactionManager ni to'g'ridan-to'g'ri ishlatish orqali transaksiyani boshqarishingiz mumkin. Buning uchun ReactiveTransactionManager ni belgilaydigan amalga oshirilishini bean orqali bering. Keyin, TransactionDefinition va ReactiveTransaction ob'ektlaridan foydalanib, transaksiyalarni boshlash, rollback va commit qilish mumkin. Quyidagi misolda bu qanday qilish kerakligi ko'rsatilgan:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// Transaksiya nomini aniq belgilash dasturiy ravishda amalga oshiriladi
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);
reactiveTx.flatMap(status -> {
Mono<Object> tx = ...; // bu yerda biznes mantiqingizni joylashtiring
return tx.then(txManager.commit(status))
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});
val def = DefaultTransactionDefinition()
// Transaksiya nomini aniq belgilash dasturiy ravishda amalga oshiriladi
def.setName("SomeTxName")
def.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
val reactiveTx = txManager.getReactiveTransaction(def)
reactiveTx.flatMap { status ->
val tx = ... // bu yerda biznes mantiqingizni joylashtiring
tx.then(txManager.commit(status))
.onErrorResume { ex -> txManager.rollback(status).then(Mono.error(ex)) }
}
GO TO FULL VERSION