Spring-in əməkdəlik abstraksiyasını anlamağın açarı, əməkdəlik strategiyası anlayışıdır. Əməkdəlik strategiyası TransactionManager, xüsusilə də org.springframework.transaction.PlatformTransactionManager
interfeysinin vasitəsilə - imperativ əməkdəliklərin idarə olunması, həmçinin org.springframework.transaction.ReactiveTransactionManager
interfeysinin vasitəsilə - reaktiv əməkdəliklərin idarə olunması ilə müəyyənləşdirilir. Növbəti kod parçası PlatformTransactionManager
API interfeysinin müəyyənləşdirilməsini göstərir:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
Bu, əsasən xidmət təminatçısı interfeysidir (SPI), baxmayaraq ki, onu proqramlı olaraq tətbiq kodundan istifadə etmək olar. PlatformTransactionManager
interfeys olduğundan, onu asanlıqla imitasiya obyekti və ya stubları kimi həyata keçirmək olar. O, JNDI kimi bir axtarış strategiyasına bağlı deyil. PlatformTransactionManager
in tətbiqləri Spring Framework IoC konteynerində hər hansı başqa obyekt (və ya bean) kimi müəyyənləşdirilir. Bu yalnız bir üstünlük Spring Framework-dən istifadə edərək əməkdəlikləri layiqli abstraksiya edir, hətta JTA ilə işləsəz belə. Əməkdəlik kodunu test etmək daha asan olur, əgər o JTA-dan birbaşa istifadə etməzsə, əlbəttə.
Yenidən Spring-in fəlsəfəsinə uyğun olaraq, TransactionException
interfeysinin hər hansı bir metodundan atıla bilən istisna istifadəçinin seçiminə buraxılmışdır (yəni java.lang.RuntimeException
sinfini genişləndirir). Əməkdəlik infrastrukturunda olan nasazlıqlar demək olar ki, həmişə kritikdir. İstisna hallarda, tətbiq kodu həqiqətən əməkdəliyin nasazlığından bərpa ola bilər, tətbiq inkişafçısı hələ də TransactionException
ni tutub idarə edə bilər. Əsas məqam odur ki, inkişafçılar bunu məcburiyyət olmadan edə bilər.
getTransaction(..)
metodu TransactionDefinition
parametrinə əsasən TransactionStatus
obyektini qaytarır. Qaytarılan TransactionStatus
yeni əməkdəliyi təmsil edə bilər və ya cari çağırış silsiləsində müvafiq bir əməkdəlik varsa mövcud əməkdəliyi təmsil edə bilər. Sonuncu halda, Java EE əməkdəlik kontekstləri ilə olduğu kimi, TransactionStatus
icra axını ilə əlaqələndirilir.
Spring Framework 5.2 versiyasından etibarən, Spring həmçinin reaktiv tipli və ya Kotlin koroutines istifadə edən reaktiv tətbiqlər üçün əməkdəlik idarəetmə abstraksiyası təqdim edir. Növbəti kod parçası org.springframework.transaction.ReactiveTransactionManager
ilə müəyyənləşdirilmiş əməkdəlik strategiyasını göstərir:
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 müəyyənləşdirir:
-
Yayılma: Adətən, əməkdəlik mövcudluq sahəsindəki bütün kod bu əməkdəlikdə icra olunur. Lakin, əməkdəlik metodu, artıq mövcud bir əməkdəlik konteksti varsa necə davranacağı üçün loqik təyin etmək olar. Məsələn, kodun icrası mövcud əməkdəlikdə (adi hal) davam edə bilər və ya mövcud əməkdəlik dayandırılıb, yeni bir əməkdəlik yaradıla bilər. Spring, EJB-dən tanış olan əməkdəlik yayılma növlərini təklif edir. Spring-də əməkdəlik yayılması semantikası ilə tanış olmaq üçün "Əməkdəlik Yayılması" bölməsinə baxın.
-
İzolasiya: Bu əməkdəliyin digər əməkdəliklərin işindən hansı dərəcədə təcrid edilmişdir. Məsələn, bu əməkdəlik digər əməkdəliklərdən təsdiq edilməmiş qeydləri görə bilərmi?
-
Gözləmə vaxtı: Əməkdəliyin icra müddəti neçə vaxt davam edəcək və əsas əməkdəlik infrastrukturu tərəfindən avtomatik olaraq geri çevriləcək.
-
Yalnız oxumaq üçün status: Kodunuzun məlumatları oxuyacağı, lakin onları dəyişdirə bilməyəcəyi rejimdə əməkdəlikdən istifadə edilə bilər. Yalnız oxumaq üçün əməkdəliklər bəzi hallarda, məsələn, Hibernate istifadə edirsinizsə, optimizasiya kontekstində faydalı ola bilər.
Bu parametrlər standart əməkdəlik anlayışlarını əks etdirir. İstifadəçilərin əməkdəlik təcrid səviyyələri və digər əsas əməkdəlik anlayışları haqqında daha çox məlumat əldə etmək üçün mənbələrə müraciət etmək zərurəti ola bilər. Bu anlayışları anlamaq, Spring Framework və ya hər hansı əməkdəlik idarəetmə həllindən istifadə etmək üçün lazımdır.
TransactionStatus
interfeysi əməkdəlik koduna heç bir maneə olmadan əməkdəliyin icrasını idarə etmək və əməkdəliyin statusunu sorğulamaq imkanı verir. Bu konsepsiyalar tanış olmalıdır, çünki onlar bütün əməkdəlik API-ləri üçün ümumidir. Növbəti kod parçası TransactionStatus
interfeysini göstərir:
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
}
Spring-də əməkdəlik idarəetməsinin hansı üsulunu seçirsinizsə - deklarativ və ya proqramlı - doğru TransactionManager
in tətbiqini müəyyənləşdirmək mütləq zəruridir. Adətən, bu tətbiq asılılıqların inyeksiyası vasitəsilə müəyyənləşdilir.
TransactionManager
tətbiqləri adətən onların işlədikləri mühiti, məsələn, JDBC, JTA, Hibernate və s., bilməyi tələb edir. Növbəti nümunələr göstərir ki, adi JDBC vasitəsilə PlatformTransactionManager
lokal həyata keçirilməsi necə müəyyən edilə bilər.
JDBC DataSource
ni aşağıdakı bənzər bir bean yaradırıqsa müəyyən edə bilərsiniz:
<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>
Sonra əlaqəli PlatformTransactionManager
bean-i DataSource
müəyyənləşdirilməsinə istinadla təmin edilir. Müəyyənləşdirmə aşağıdakı nümunədəki kimi olmalıdır:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Əgər Java EE konteynerində JTA istifadə edirsinizsə, Spring-dən JtaTransactionManager
ilə birlikdə JNDI vasitəsilə əldə edilmiş konteyner DataSource
istifadə edirsinizsə, JTA və JNDI-nin axtarışı versiyası aşağıdakı kimi görünəcəyi göstərilir:
<?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" />
<!-- digər <bean/--> müəyyənləşdirmələri -->
</beans>
JtaTransactionManager
DataSource
(və ya hər hansı digər xüsusi resurslar) haqqında bilməyə ehtiyac yoxdur, çünki o, konteynerin qlobal əməkdəlik idarəetmə infrastrukturundan istifadə edir.
dataSource
bean-i müəyyənləşdirməsində
<jndi-lookup/>
etiketi
jee
namespacesindən istifadə olunur. Daha ətraflı məlumat üçün baxın
"JEE Şeması" bölməsinə.
Hər hansı bir təyin edilmiş əməkdəlik dəyərləri dəsti ilə Spring tətbiq kodunu dəyişmək lazım deyil. Əməkdəlik idarəetmə üsulunu dəyişdirmək, təkcə konfiqurasiyanı dəyişdirərək, hətta bu dəyişikliyin lokaldan qlobal əməkdəliklərə keçməsi olsa belə, mümkündür.
Hibernate Əməkdəliklərini Konfiqurasiya Etmək
Hibernate-dən lokal əməkdəlikləri asanlıqla istifadə etmək də mümkündür, növbəti nümunələrdə göstərildiyi kimi. Bu halda, tətbiq kodunuz Hibernate-dən Session
obyektlərini almaq üçün istifadə edə biləcəyiniz LocalSessionFactoryBean
müəyyənləşdirməlisiniz.
Yerel JDBC nümunəsində göstərildiyi kimi DataSource
bean-i müəyyənləşdirməsi ilə oxşardır, dolayısıyla növbəti nümunələrdə göstərilmir.
DataSource
nin axtarışı (hər hansı bir qeyri-JTA əməkdəlik manoqeriylə birlikdə) JNDI vasitəsilə həyata keçirilirsə və idarəetmə Java EE vasitəsilə həyata keçirilirsə, o qeyri-əməkdəlik olmalıdır, çünki Spring Framework (və ya Java EE konteyneri deyil) əməkdəlikləri idarə edir.
Bu halda, txManager
bean-i HibernateTransactionManager
-nin tipinə malikdir. Eynilə DataSourceTransactionManager
-nin DataSource
-yə istinadlara ehtiyacı olduğu kimi, HibernateTransactionManager
-nin SessionFactory
-yə istinadlara ehtiyacı var. Növbəti nümunədə sessionFactory
və txManager
bean-ləri elan edilib:
<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>
Əgər Hibernate və JTA ilə idarə olunan konteyner Java EE əməkdəliklərini istifadə edirsinizsə, əvvəlki JTA ilə JDBC nümunəsində olduğu kimi eyni JtaTransactionManager
dən istifadə etməlisiniz, bu növbəti nümunədə göstərilmişdir. Hibernate'in JTA-dan koordinasiya edicisi və bəlkə də bağlantı azadlıq rejimi konfiqurasiyası vasitəsi ilə xəbərdar olması tövsiyə olunur:
<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"/>
Və ya eyni standart dəyərləri təmin etmək üçün LocalSessionFactoryBean
ə JtaTransactionManager
yollaya bilərsiniz:
<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