JavaRush /Kurslar /All lectures for UZ purposes /Transaksiyalarni dasturiy boshqarish

Transaksiyalarni dasturiy boshqarish

All lectures for UZ purposes
Daraja, Dars
Mavjud

Spring Framework dasturiy boshqarish transaksiyalarini bajarish uchun ikki usul taklif qiladi:

  • TransactionTemplate yoki TransactionalOperator.

  • Bevosita TransactionManager ni 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.

Quyidagi misollarda ko'rsatilganidek, 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:

Java
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();
            }
        });
    }
}
Kotlin
// 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:

Java
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        updateOperation1();
        updateOperation2();
    }
});
Kotlin
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:

Java
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        try {
            updateOperation1();
            updateOperation2();
        } catch (SomeBusinessException ex) {
            status.setRollbackOnly(); // Faqat rollback
        }
    }
});
Kotlin
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:

Java
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...
    }
}
Kotlin
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.

Quyidagi misollarda ko'rsatilganidek, 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:

Java
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);
    }
}
Kotlin
// 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:

Java
transactionalOperator.execute(new TransactionCallback<>() {
    public Mono<Object> doInTransaction(ReactiveTransaction status) {
        return updateOperation1().then(updateOperation2)
                    .doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
        }
    }
});
Kotlin
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:

Java
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);
    }
}
Kotlin
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:

Java
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);
Kotlin
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:

Java
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)));
});
Kotlin
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)) }
}
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION