Spring'деги транзакция абстракциясын түшүнүүнүн негизги ачкычы - бул транзакциялык стратегия түшүнүгү. Транзакциялык стратегия TransactionManager менен аныкталат, тактап айтканда org.springframework.transaction.PlatformTransactionManager
интерфейси - императивдик транзакцияларды башкаруу үчүн, жана org.springframework.transaction.ReactiveTransactionManager
интерфейси - реактивдик транзакцияларды башкаруу үчүн. Төмөнкү листингде PlatformTransactionManager
API-интерфейсинин аныктамасы көрсөтүлгөн:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
Бул негизинен кызмат көрсөтүүчү интерфейс (SPI), бирок аны колдонмодогу коддон программалык түрдө колдонууга болот. PlatformTransactionManager
интерфейс болгондуктан, керек болгондо аны оңой эле кыялданган объект же "заглушка" функциясы катары ишке ашырууга болот. Ал JNDI сыяктуу издөө стратегиясына байланбаган. PlatformTransactionManager
ишке ашыруусу Spring Framework ичиндеги IoC-контейнериндеги башка объект (же бин) сыяктуу эле аныкталат. Ушунун өзү эле транзакцияларды Spring Frameworkтөн татыктуу абстракция кылат, сиз JTA менен иштесеңиз дагы. Транзакциялык кодду сыноо JTAны түздөн-түз колдонгондо караганда бир кыйла жеңил болот.
Жанатан алдыда, Spring философиясына ылайык, тилкеде PlatformTransactionManager
интерфейсинин кандайдыр бир методдору аркылуу жаралган TransactionException
текшерилбеген (б.а. java.lang.RuntimeException
классынан кеңейет) болуп саналат. Транзакция инфраструктурасынын бузулуулары дээрлик дайыма такыр өчпөйт. Колдонмо коду транзакциянын бузулушунан чыгуучу сейрек учурларда, колдонмо иштеп чыгуучу TransactionException
кармап, иштеп чыгууну колго ала алат. Маанилүү аспекти - бул иштеп чыгуучулар муну мажбурлоосу жок жасап алса болот.
getTransaction(..)
методу TransactionDefinition
параметрине жараша TransactionStatus
объектин кайтарат. Кайткан TransactionStatus
жаңы транзакцияны көрсөтүшү мүмкүн, же учурдагы чакыруучу стекде ылайыктуу транзакция бар болсо, учурдагы транзакцияны көрсөтүшү мүмкүн. Акыркы учурда, Java EE транзакциялык контексттеринде болгондой, TransactionStatus
аткаруу агымы менен байланыштуу.
Spring Framework 5.2 версиясынан баштап, Spring реактивдик түрлөрдү же Kotlin корутиндерин колдонгон реактивдик тиркемелер үчүн транзакцияларды башкаруу абстракциясын да камсыз кылат. Төмөнкү листингде org.springframework.transaction.ReactiveTransactionManager
аркылуу аныкталган транзакциялык стратегия көрсөтүлгөн:
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
интерфейси төмөндөкүлөрдү аныктайт:
-
Таратуу: Жалпысынан, транзакциянын жеткиликтүүлүк аймагындагы бардык код бул транзакцияда аткарылат. Бирок, транзакциялык контекст мурунтан эле бар болгондо, транзакциялык метод ишке кирүүгө логикасын аныктаса болот. Мисалы, кодду аткаруу учурдагы транзакцияда (кадимки учур) улантылышы мүмкүн же бар транзакция токтотулуп, жаңы транзакция түзүлүшү мүмкүн. Spring CMT аркылуу EJB транзакцияларын таратуунун ар кандай түрлөрүн сунуштайт. Springдеги транзакцияларды таратуунун семантикасы менен таанышуу үчүн, "Транзакцияларды таратуу" бөлүмүн караңыз.
-
Жолтоо: Берилген транзакция башка транзакциялардын ишинен канчалык деңгээлде акысыз экенин аныктайт. Мисалы, бул транзакция башка транзакциялардын аягына чыкпаган жазууларын көрө алабы?
-
Күтүү убактысы: Транзакциянын аяктаганга чейин иштөө узактыгы жана негизги транзакция инфраструктурасы тарабынан автоматтык түрдө артка кайтарылышы.
-
Тандамал режим: Сиз транзакцияны "окуу гана" режиминде колдоно аласыз, анда сиздин кодуңуз маалыматтарды окуйт, бирок өзгөртө албайт. Мындай "окуу гана" транзакциялар айрым учурларда оптималдаштыруу контекстинде пайдалуу болушу мүмкүн, мисалы, сиз Hibernate колдонуп жатсаңыз.
Бул параметрлер стандарттык транзакция түшүнүктөрүн чагылдырат. Транзакция обочолонуу деңгээлдери жана башка негизги түшүнүктөр боюнча маалымат алууда, керек болсо булактарды карап чыгышыңыз керек. Бул түшүнүктөрдү Spring Framework же транзакцияларды башкаруу боюнча башка чечимди колдонуу үчүн түшүнүү керек.
TransactionStatus
интерфейси транзакциялык кодго тоскоолдуксуз транзакциянын аткарылушун башкарууга жана анын статусун суроого мүмкүндүк берет. Түшүнүктөр жалпы болгондо тааныш болушу керек, анткени алар бардык транзакциялык API интерфейстерине мүнөздүү. Төмөнкү листингде TransactionStatus
интерфейси көрсөтүлгөн:
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
}
Springдеги транзакцияларды башкаруунун кайсы жолун тандаганыңызга карабастан - декларативдүү же программалык - туура TransactionManager
ишке ашыруусун аныктоо абдан маанилүү. Бул ишке ашыруу адатта көз карандылыктарды киргизүү аркылуу аныкталат.
TransactionManager
ишке ашыруулары адатта алар иштеген чөйрөнү, мисалы JDBC, JTA, Hibernate жана башка ушул сыяктууларды билүүнү талап кылат. Төмөнкү мисалдарда кадимки JDBC колдонулуп, локалдык PlatformTransactionManager
ишке ашыруусун кантип аныктоо көрсөтүлгөн.
Сиз JDBC'нин DataSource
аныктап, төмөндөгү сыяктуу бин түзүү аркылуу аныктай аласыз:
<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>
Байланышкан PlatformTransactionManager
бининин аныктамасы андан соң DataSource
аныктамасына шилтеме менен камсыздалат. Аныктама төмөнкү мисалда көрсөтүлгөнгө окшош болушу керек:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Эгерде сиз Java EE контейнеринде JTA колдонуп жатсаңыз, анда Spring'ден JtaTransactionManager
менен биргеликте JNDI аркылуу алынган контейнердик DataSource
колдоносуз. Кийинки мисалда JTA жана JNDI аркылуу издөө версиясы кандай экенин көрсөтөт:
<?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" />
<!-- башка аныктамалар <bean/--> -->
</beans>
JtaTransactionManager
үчүн DataSource
(же башка өзгөчө ресурстар) жөнүндө билүүсү кереги жок, анткени ал контейнердин глобалдык транзакция башкаруу инфраструктурасын колдонууга тартат.
dataSource
бининин аныктамасында
jee
аталыш мейкиндигинен
<jndi-lookup/>
теги колдонулат. Көбүрөөк маалымат алуу үчүн,
"JEE схемасы" бөлүмүн караңыз.
Транзакцияларга тапшырылган топтом кандай болсо дагы, колдонмо коду өзгөртүлбөшү керек. Транзакцияларды башкаруу ыкмасын жөн гана конфигурациясын өзгөртүү аркылуу алмаштырса болот, бул өзгөрүү жергиликтүү транзакциялардан глобалдыкка же тескериниме өтүүгө алып келсе дагы.
Hibernate транзакцияларын настройка кылуу
Ошондой эле, алдыдагы мисалдарда көрсөтүлгөндөй, Hibernateден жергиликтүү транзакцияларды колдонуу оңой. Бул учурда, сиздин колдонмоңуз Session
экземплярларын алуу үчүн иштете ала турган LocalSessionFactoryBean
аныктоо керек.
DataSource
бининин аныктамасы мурунку жергиликтүү JDBC мисалы менен окшош болгондуктан, төмөнкү мисалда көрсөтүлбөйт.
DataSource
маалымат булагынын издөөсү (кез келген JTA эмес транзакция диспетчери тарабынан жүргүзүлөт) JNDI аркылуу жүргүзүлсө жана Java EE аркылуу башкарылса, анда ал транзакциялык болбошу керек, анткени Spring Framework (Java EE контейнер эмес) транзакцияларды башкарууга жооп берет.
Бул учурда txManager
бининин типи HibernateTransactionManager
. DataSourceTransactionManager
сыяктуу эле, HibernateTransactionManager
да SessionFactory
шилтемесине муктаж. Төмөнкү мисалда sessionFactory
жана txManager
бининин аныктамасы берилген:
<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>
Эгерде сиз Hibernate жана Java EE тарабынан башкарылган JTA транзакцияларын колдонуп жатсаңыз, мурунку JDBC үчүн JTA мисалындагыдай эле JtaTransactionManager
колдонуу керек, тагыраагы төмөнкү мисалда көрсөтүлгөндөй. Ошондой эле, Hibernate'ти JTA жөнүндө анын транзакция координатору жана мүмкүн болушунча түзмө-түз байланыш режиминин конфигурациясы аркылуу кабардар кылуу сунушталат:
<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"/>
Же LocalSessionFactoryBean
'ге JtaTransactionManager
'ди өткөрүп, стандарттуу маани берсеңиз болот:
<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