JavaRush /Курстар /All lectures for KY purposes /Транзакция абстракциясынын түшүнүгү

Транзакция абстракциясынын түшүнүгү

All lectures for KY purposes
Деңгээл , Сабак
жеткиликтүү

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 схемасы" бөлүмүн караңыз.
Эгерде сиз JTA колдонгон болсоңуз, транзакция диспетчерин аныктамасы кандай гана маалыматка жетүү технологиясы колдонулбасын, бирдей болушу керек, ал JDBC, Hibernate аркылуу JPA же башка колдоого алынган технология болсо дагы. Бул JTA транзакциялары глобалдык транзакциялар болуп эсептелет, анткени алар каалаган транзакциялык ресурска катыша алышат.

Транзакцияларга тапшырылган топтом кандай болсо дагы, колдонмо коду өзгөртүлбөшү керек. Транзакцияларды башкаруу ыкмасын жөн гана конфигурациясын өзгөртүү аркылуу алмаштырса болот, бул өзгөрүү жергиликтүү транзакциялардан глобалдыкка же тескериниме өтүүгө алып келсе дагы.

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"/>
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION