Spring transaksiyalarini abstraktsiyasini tushunishning kaliti bu tranzaktsion strategiya tushunchasi hisoblanadi. Tranzaktsion strategiya TransactionManager tomonidan aniqlanadi, xususan interface org.springframework.transaction.PlatformTransactionManager – imtimerativ tranzaktsiyalarni boshqarish uchun, va interface org.springframework.transaction.ReactiveTransactionManager – reaktiv tranzaktsiyalarni boshqarish uchun. Quyidagi listingda PlatformTransactionManager API interfeysining aniqlanishi ko'rsatilgan:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
Bu asosan servis provayder interfeysi (SPI), lekin uni dasturiy ravishda ilova kodidan foydalanish mumkin. PlatformTransactionManager interfeys bo'lganligi sababli, uni kerak bo'lganda mock obyekt yoki stub funksiya sifatida osongina amalga oshirish mumkin. U JNDI kabi qidiruv strategiyasiga bog‘liq emas. PlatformTransactionManager realizatsiyalari Spring Framework IoC konteyneridagi har qanday boshqa obyekt (yoki bin) sifatida aniqlangan. Birgina shu afzallik, agar siz JTA bilan ishlayotgan bo'lsangiz ham, Spring Framework transaksiyalarini munosib abstraksiya qiladi. Transaksion kodni JTA bilan to'g'ridan-to'g'ri ishlaganga qaraganda ancha osonroq sinash mumkin.
Spring falsafasiga muvofiq, interfeysdan har qanday metod tomonidan ishlab chiqarilishi mumkin bo'lgan TransactionException istisnosi tekshirilmaydi (ya'ni java.lang.RuntimeException sinfini kengaytiradi). Infratuzilma transaksiyalaridagi nosozliklar deyarli har doim kritik bo'ladi. Dastur kodi haqiqatdan ham transaktsiya nosozligi sababli tiklanishi mumkin bo'lgan kamdan-kam hollarda, dasturni ishlab chiquvchi hali ham TransactionException ni ushlab qolish va qayta ishlashni amalga oshirishi mumkin. Muhimi shundaki, ishlab chiquvchilar buni qila olishlari majburiyatsiz.
getTransaction(..) metodi TransactionDefinition parametriga qarab TransactionStatus obyektini qaytaradi. Qaytarilgan TransactionStatus yangi tranzaksiyani ifodalashi yoki joriy qo'ng'iroqlar stackida mos keluvchi tranzaksiya mavjud bo'lsa, mavjud tranzaksiyani ifodalashi mumkin. Ikkinchi hollarda, Java EE transaktsion kontekstlarida bo'lgani kabi, TransactionStatus ijro potokiga bog'liq bo'ladi.
Spring Framework 5.2 versiyasidan boshlab, Spring reaktiv turlari yoki Kotlin korutinlaridan foydalanadigan reaktiv ilovalar uchun tranzaktsiyalarni boshqarish abstraksiyasini ham taqdim etadi. Quyidagi listingda org.springframework.transaction.ReactiveTransactionManager tomonidan aniqlangan tranzaktsion strategiya ko'rsatilgan:
public interface ReactiveTransactionManager extends TransactionManager {
Mono<ReactiveTransaction> getReactiveTransaction(TransactionDefinition definition) throws TransactionException;
Mono<Void> commit(ReactiveTransaction status) throws TransactionException;
Mono<Void> rollback(ReactiveTransaction status) throws TransactionException;
}
TransactionDefinition interfeysi quyidagilarni aniqlaydi:
-
Propegatsiya: Odatda, tranzaksiya doirasida mavjud bo'lgan barcha kod ushbu tranzaksiyada amalga oshiriladi. Biroq, agar transaktsiyaviy metod ishga tushirilganda transaktsion kontekst allaqachon mavjud bo'lsa, ishlash mantiqini belgilash mumkin. Masalan, kodni bajirish mavjud tranzaktsiyada davom etishi mumkin (odatiy holat) yoki mavjud tranzaktsiya to'xtatilishi va yangi tranzaktsiya yaratilishi mumkin. Spring EJB-dagi CMT'ga tanish bo'lgan har qanday transaktsiya propegatsiya variantlarini taklif etadi. Spring'dagi transaktsiya propegatsiyasi semantikasini tushunish uchun, "Transaktsiyalarni propegatsiyasi" bo'limiga qarang.
-
Izolyatsiya: Ushbu tranzaktsiya boshqa tranzaksiyalar ishidan qanchalik izolyatsiya qilinganligi. Masalan, bu tranzaksiya boshqa tranzaksiyalardan kelib chiqadigan xatolarni ko'rishi mumkinmi?
-
Kuting vaqti: Tranzaksiya bajarilishining davomiyligi va asosiy infratuzilma orqali avtomatik ravishda bekor qilinishi.
-
Faqat o'qish statusi: Tranzaksiyani "faqat o'qish" rejimida ishlatish mumkin bo'lib, bu sizning kodingiz ma'lumotlarni o'qiydi, ammo o'zgartira olmaydi. "Faqat o'qish" tranzaktsiyalari ba'zi hollarda, masalan, siz Hibernate'dan foydalansangiz, optimallashtirish kontekstida foydali bo'lishi mumkin.
Bu parametrlar tranzaktsiyaning standart tushunchalarini aks ettiradi. Izolyatsiya darajasi va boshqa asosiy tranzaksiyalar tushunchalari haqida tushunganingizda, zarur bo'lgan manbalarga murojaat qiling. Bu tushunchalarni tushunish Spring Framework yoki tranzaktsiyalarni boshqarish yechimini to'g'ri qo'llash uchun zarur.
TransactionStatus interfeysi tranzaktsiyalangan kodni to'siqlarsiz tranzaksiyani boshqarishni va tranzaksiyaning holatini so'rashni ta'minlaydi. Tushunchalar tanish bo'lishi kerak, chunki ular barcha tranzaktsiya API interfeyslari uchun umumiydir. Quyidagi listingda TransactionStatus interfeysi ko'rsatilgan:
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
}
Spring'da tranzaksiyalarni boshqarish usulidan qat'i nazar - deklarativ yoki dasturiy - to'g'ri TransactionManager realizatsiyasini aniqlash mutlaqo zarur. Odatda bu realizatsiya dependency injection orqali aniqlanadi.
TransactionManager realizatsiyalari odatda ular ishlayotgan muhitni bilishni talab qiladi: JDBC, JTA, Hibernate va hokazo. Quyidagi misollarda qanday qilib PlatformTransactionManager'ning mahalliy realizatsiyasini (bu yerda oddiy JDBC yordamida) belgilashingiz mumkinligi ko'rsatilgan.
Siz JDBC DataSource'ni quyidagi kabi bir bin yarating:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
Keyin PlatformTransactionManager'ga oid bin DataSource aniqlashiga ko'rsatma bilan ta'minlanadi. Aniqlash quyidagi misolda ko'rsatilgandek ko'rinishi kerak:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Agar siz Java EE konteynerida JTA'dan foydalansangiz, siz konteyner tomonidan boshqariladigan DataSource'dan foydalanasiz, bu esa JNDI orqali olingan va Spring'dan JtaTransactionManager bilan birlashtirilgan. Keyingi misolda JTA va JNDI orqali qidirish versiyasi qanday ko'rinishini ko'rsatadi:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
https://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- boshqa bin ta'riflari <bean/--> -->
</beans>
JtaTransactionManager DataSource (yoki boshqa maxsus resurslar) haqida bilishi shart emas, chunki u konteynerning global tranzaktsiyalar infratuzilmasidan foydalanadi.
dataSource bin ta'rifida
jee nom maydonidan
<jndi-lookup/> tegidan foydalanilgan. Qo'shimcha ma'lumot uchun
"JEE Shemа" bo'limiga qarang.
Spring tranzaktsiyalar uchun berilgan har qanday parametrlar to'plami bilan, ilova kodini o'zgartirish shart emas. Agar bu o'zgarish mahalliy tranzaksiyalardan global tranzaksiyalarga o'tishni anglatadigan bo'lsa ham, tranzaktsiyalarni boshqarish usulini faqat sozlamani o'zgartirish orqali o'zgartirishingiz mumkin.
Hibernate Tranzaktsiyalarini Sozlash
Keyingi misollarda ko'rib turganingizdek, Hibernate'dan mahalliy tranzaksiyalarni ishlatish oson. Bu holda, Hibernate uchun LocalSessionFactoryBeanni aniqlashni amalga oshirishingiz kerak, va sizning ilovangiz kodi Hibernate'dan Session instance lаrini olish uchun uni ishlatishi mumkin.
DataSource bin ta'rifi avvalgi mahalliy JDBC misoli kabi ko'rinadi, shuning uchun quyidagi misolda ko'rsatilmagan.
DataSource izlash JNDI orqali amalga oshirilsa va Java EE tomonidan boshqarilsa, u no-transaktsiyaviy bo'lishi kerak, chunki Spring Framework (va Java EE konteyneri emas) tranzaksiyalarni boshqaradi.
Bu holda txManager bin HibernateTransactionManager tipida bo'ladi. Xuddi DataSourceTransactionManager uchun DataSource'ga ishora kerak bo'lgani kabi, HibernateTransactionManager'ga SessionFactory'ga ishora kerak. Quyidagi misolda sessionFactory va txManager binlari deklaratsiya qilingan:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Agar siz Hibernate va Java EE tomonidan boshqariladigan JTA tranzaksiyalaridan foydalansangiz, siz JDBC uchun JTA bilan bir xil JtaTransactionManager'dan foydalanishingiz kerak, quyidagi misolda ko'rinishini ko'rsatadi. Shuningdek, Hibernate JTA haqida o'z tranzaktsiyalar koordinatori va ehtimol ulanishni bo'shatish rejimi orqali bilishi kerak:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.transaction.coordinator_class=jta
hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
Yoki siz LocalSessionFactoryBean'ga JtaTransactionManager ni uzatishingiz mumkin, bu bir xil sukut qilingan qiymatlarni ta'minlash uchun:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
<property name="jtaTransactionManager" ref="txManager"/>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
GO TO FULL VERSION