Hibernate

All lectures for UZ purposes
Daraja, Dars
Mavjud

Spring bilan birga Hibernate 5 ni ko'rib chiqishdan boshlaymiz, uni Springning OR-mapping vositalarini integratsiya qilish yondashuvini ko'rsatish uchun ishlatamiz. Bu bo'limda ko'plab savollar chuqur yoritilgan va DAO va tranzaktsiyalarni ajratishning turli xil variantlari ko'rsatilgan. Ushbu andozalarning aksariyati boshqa qo'llab-quvvatlanadigan ORM vositalariga bevosita o'tkazilishi mumkin. Ushbu bobning keyingi qismlarida boshqa ORM-texnologiyalari va qisqa misollar keltirilgan.

Spring Framework 5.3 versiyasidan boshlab, Spring HibernateJpaVendorAdapter uchun, shuningdek Hibernate'dan SessionFactory ni o'rnatish uchun Hibernate ORM 5.2+ talab qiladi. Hibernate ORM 5.4 ni hozirgina ishga tushirilgan loyihalar uchun ishlatishni tavsiya qilamiz. HibernateJpaVendorAdapter bilan ishlatish uchun Hibernate Search'ni 5.11.6 versiyasiga yangilash kerak.

Spring konteynerida SessionFactory sozlash

Dastur obyektlarini resurslarni (masalan, JDBC'dan DataSource yoki Hibernate'dan SessionFactory) qattiq kodlangan izlashga bog'lamaslik uchun, ularni Spring konteynerida binlar sifatida aniqlash mumkin. Resurslarga kirish kerak bo'lgan dastur obyektlari bunday oldindan tayyorlangan nusxalarga binlar orqali kirishadi, bu DAO aniqlashda keyingi bo'limda ko'rsatilgan.

Ilova kontekstini XML orqali aniqlashning keyingi namunasi JDBC dan DataSource va Hibernate'dan SessionFactory ni qanday qilib o'rnatishni ko'rsatadi:

<beans>
    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
        <property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>
    <bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <property name="mappingResources">
            <list>
                <value>product.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.HSQLDialect
            </value>
        </property>
    </bean>
</beans>

Lokal BasicDataSource ni Jakarta Commons DBCP'dan JNDI da joylashgan DataSource ga (odatda ilova serveri tomonidan boshqariladi) o'tish faqat konfiguratsiya masalasidir, bu keyingi misolda ko'rsatilgan:

<beans>
    <jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/>
</beans>

Bundan tashqari, SessionFactory ni JNDI dan olish uchun Spring'dan JndiObjectFactoryBean / <jee:jndi-lookup> dan foydalanish mumkin. Biroq, bu odatda EJB kontekstidan tashqarida noan'anaviy yechim hisoblanadi.

Spring shuningdek LocalSessionFactoryBuilder variantini taqdim etadi, bu esa @Bean va dasturiy o'rnatishga asoslangan konfiguratsiya bilan osonlikcha integratsiya qiladi (hech qanday FactoryBean ishtirokisiz).

Ham LocalSessionFactoryBean, ham LocalSessionFactoryBuilder foniy yuklashni qo'llab-quvvatlaydi, shu bilan Hibernate yuki yuklovchi jarayonning amalga oshiruvchisi uchun (masalan, SimpleAsyncTaskExecutor) foniy yuklash oqimiga parallel ravishda amalga oshiriladi. LocalSessionFactoryBean uchun bu bootstrapExecutor xususiyati orqali mavjud. dasturiy LocalSessionFactoryBuilder da yuklanishni amalga oshiruvchi argumentni qabul qiladigan buildSessionFactory usulining ortiqcha yuklangan versiyasi mavjud.

Spring Framework 5.1 dan boshlab, bunday native Hibernate sozlash "JPA uchun native Hibernate sozlash" bo'limida batafsilroq keltirilgan umumiy JPA-farqi bilan birga Hibernate'dan EntityManagerFactory ni ochishi mumkin.

Oddiy Hibernate API interfeysiga asoslangan DAO'ni amalga oshirish

Hibernate'da kontekstli sessiyalar deb ataluvchi funksiya bor, unda Hibernate har bir tranzaktsiya uchun bir joriy Sessionni o'zi boshqaradi. Bu Springda har bir tranzaktsiya uchun bitta Hibernate Sessionni sinxronizatsiya qilishga deyarli teng keladi. Mos keluvchi DAO amalga oshirilishi oddiy Hibernate API interfeysiga asoslangan quyidagi misolga o'xshaydi:

Java
public class ProductDaoImpl implements ProductDao {
    private SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    public Collection loadProductsByCategory(String category) {
        return this.sessionFactory.getCurrentSession()
                .createQuery("from test.Product product where product.category=?")
                .setParameter(0, category)
                .list();
    }
}
Kotlin
class ProductDaoImpl(private val sessionFactory: SessionFactory) : ProductDao {
    fun loadProductsByCategory(category: String): Collection<*> {
        return sessionFactory.currentSession
                .createQuery("from test.Product product where product.category=?")
                .setParameter(0, category)
                .list()
    }
}

Bu stil Hibernate qo'llanmasi va misollaridan olingan, faqat SessionFactory mahalliy o'zgaruvchida saqlangan. Biz bunday mahalliy usulga asoslangan sozlashni tavsiya qilamiz, eski HibernateUtil klassidan emas, Hibernate buni CaveatEmptor dastur misolida ko'rsatgan. (Umuman olganda, resurslarni statik o'zgaruvchilarda saqlash shart bo'lmasa, bunga yo'l qo'ymaslik kerak).

Yuqoridagi DAO misoli bog'liklikni in'ektsiya qilish namunasi hisoblanadi. U Spring IoC konteyneriga juda yaxshi mos tushadi, xuddi agar u Spring'dan HibernateTemplate namunasiga asoslangan holda yozilgan bo'lsa, yoki oddiy Java-da, masalan, modul testlarida ham ishlaydi. Buning uchun uning nusxasini yarating va kerakli fabrika havolasini setSessionFactory(..) da chaqiring. Bir Spring beani aniqlashda, DAO obyekt quyidagicha ko'rinadi:

<beans>
    <bean id="myProductDao" class="product.ProductDaoImpl">
        <property name="sessionFactory" ref="mySessionFactory"/>
    </bean>
</beans>

Bu DAO uslubining asosiy afzalligi uning faqatgina Hibernate API interfeysiga bog'liq bo'lib, hech qanday Spring klassini import qilmaslikdir. Bu yaxshi va aniq ko'rinadi va Hibernate dasturchilariga tabiiyroq ko'rinishi mumkin.

Biroq, DAO HibernateException ni (bu tekshirilmagan, shu sababli uni e'lon qilish yoki ushlash shart emas) yaratadi, bu esa chaqiruvchi dasturlar faqat tan olingan o'ta muhim xatolar bilan ishlashlarini anglatadi, agar Hibernate'ning o'zi istisnolar iyerarxiyasiga bog'lanish istamasalar. Maxsus sabablarga (masalan, optimistik blokirovkadan muvaffaqiyatsizlik) oydinlik kiritish mumkin emas, bundan tashqari chaqiruvchi dastur amalga oshirish strategiyasiga bog'langan bo'ladi. Bunday muvofiqlashtirish Hibernate asosida keng asoslangan dasturlar uchun, maxsus istisnolarni ishlatishni talab qilmaydigan ko'rinishi mumkin. Yaxshiyamki, Spring'dan LocalSessionFactoryBean orqali har qanday Spring tranzaktsiya strategiyasi uchun Hibernate yordamida tranzaktsion Session ni qaytaradi, hatto HibernateTransactionManager bilan ishlatilganida ham. Bu usulning standart logikasi, har qanday mavjud JTA tranzaktsiyasi bilan bog'liq bo'lgan joriy Session ni qaytarish hisoblanadi. Bu logika, siz Spring'dan JtaTransactionManager ni ishlatasizmi, konteyner tomonidan boshqariladigan tranzaktsiyalar (CMT tranzaktsiyalari) yoki JTA interfeysi orqali foydalanasizmi, muhimdir.

Umuman olganda, oddiy Hibernate API interfeysiga asoslangan DAO'larni amalga oshirish mumkin, lekin ular Spring tomonidan boshqariladigan tranzaktsiyalarda ishlatilishi mumkin.

Deklarativ tranzaktsiyalarni ajratish

Spring deklarativ tranzaktsiyalarni qo'llab-quvvatlashni tavsiya qilamiz, bu esa Java kodidagi tranzaktsiyalarni ajratish uchun API chaqiriqlarini almashtirib, AOP tranzaktsiya interceptorini sozlash imkoniyatini beradi. Ushbu tranzaktsiyalarni Spring konteynerida, Java yoki XML an'otatsiyalaridan foydalanish orqali sozlashingiz mumkin. Ushbu imkoniyat orqali deklarativ tranzaktsiyalarni foydalanishingiz mumkin, bu biznes xilma-xilliklarning tranzaktsiyalarni ajratish kodini chiqarib, asosiy ma'noni kiritishiga e'tibor beradi.

Davom etishdan oldin, agar hali o'qimagan bo'lsangiz, "Deklarativ tranzaktsiyalarni boshqarish" bo'limini o'qishingizni tavsiya qilamiz.

Siz xizmatlar darajasini @Transactional an'otatsiyalari bilan belgilang va Spring konteyneridan ushbu an'otatsiyalarning izlanishini va bu an'otatsiyalangan metodlar uchun tranzaktsion semantika ta'minlashini so'rang. Quyidagi misolda bu qanday amalga oshirilishi ko'rsatilgan:

Java
public class ProductServiceImpl implements ProductService {
    private ProductDao productDao;
    public void setProductDao(ProductDao productDao) {
        this.productDao = productDao;
    }
    @Transactional
    public void increasePriceOfAllProductsInCategory(final String category) {
        List productsToChange = this.productDao.loadProductsByCategory(category);
        // ...
    }
    @Transactional(readOnly = true)
    public List<Product> findAllProducts() {
        return this.productDao.findAllProducts();
    }
}
Kotlin
class ProductServiceImpl(private val productDao: ProductDao) : ProductService {
    @Transactional
    fun increasePriceOfAllProductsInCategory(category: String) {
        val productsToChange = productDao.loadProductsByCategory(category)
        // ...
    }
    @Transactional(readOnly = true)
    fun findAllProducts() = productDao.findAllProducts()
}

Konteynerda PlatformTransactionManager ni (bean sifatida) va <tx:annotation-driven/> yozuvini sozlash kerak, bu esa @Transactional an'otatsiyalarini ishlatish uchun imkon beradi. Quyidagi misolda bu qanday amalga oshirilishi ko'rsatilgan:

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- SessionFactory, DataSource va hokazo ko'rsatilmagan -->
    <bean id="transactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <tx:annotation-driven/>
    <bean id="myProductService" class="product.SimpleProductService">
        <property name="productDao" ref="myProductDao"/>
    </bean>
</beans>

Dasturiy tranzaktsiyalarni ajratish

Tranzaktsiyalarni ilovaning yuqori darajasida ajratish mumkin, past darajadagi ma'lumotlar kirish xizmatlari ustida, har qanday miqdordagi operatsiyalarni o'z ichiga olishi mumkin. Shuningdek, har qanday biznes xizmatini amalga oshirishda cheklanish yo'q. Faqatgina PlatformTransactionManager ni Springdan olish kerak. Yana, oxirgisiga barcha joydan kirish mumkin, lekin afzalroq uni bean havolasi sifatida olish setTransactionManager(..) usuli orqali. Bundan tashqari, productDAO ni setProductDao(..) usuli orqali o'rnatish kerak. Quyidagi ikki fragmentda tranzaktsiya menejeri va Spring dastur kontekstidagi biznes xizmatini aniqlash va biznes usulining misolini ko'rsatadi:

<beans>
    <bean id="myTxManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory"/>
    </bean>
    <bean id="myProductService" class="product.ProductServiceImpl">
        <property name="transactionManager" ref="myTxManager"/>
        <property name="productDao" ref="myProductDao"/>
    </bean>
</beans>
Java
public class ProductServiceImpl implements ProductService {
    private TransactionTemplate transactionTemplate;
    private ProductDao productDao;
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }
    public void setProductDao(ProductDao productDao) {
        this.productDao = productDao;
    }
    public void increasePriceOfAllProductsInCategory(final String category) {
        this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            public void doInTransactionWithoutResult(TransactionStatus status) {
                List productsToChange = this.productDao.loadProductsByCategory(category);
                // narxlar oshiryapmiz...
            }
        });
    }
}
Kotlin
class ProductServiceImpl(transactionManager: PlatformTransactionManager,
                        private val productDao: ProductDao) : ProductService {
    private val transactionTemplate = TransactionTemplate(transactionManager)
    fun increasePriceOfAllProductsInCategory(category: String) {
        transactionTemplate.execute {
            val productsToChange = productDao.loadProductsByCategory(category)
            // narxlar oshiryapmiz...
        }
    }
}

TransactionInterceptor ni Spring dan bo'lgan har qanday tekshiriladigan dasturiy istisnoni qaytarishi mumkin, TransactionTemplate esa qaytarmasdan istisnolardan cheklangan. TransactionTemplate qaytarmas dasturiy istisnosi mavjud bo'lsa yoki dastur tomonidan qaytarmaga aytilgan bo'lsa (sifatida o'rnatiladi TransactionStatus) faylni orqaga qaytaradi. Asosiy TransactionInterceptor usulda shu tarzda ishlaydi, lekin har bir usul uchun qaytarmalarni sozlash imkonini beradi.

Tranzaktsiyalarni boshqarish strategiyalari

Ikki TransactionTemplate va TransactionInterceptor, haqiqiy tranzaktsiya ishlov berish uchun PlatformTransactionManager ga (bu mumkin HibernateTransactionManager (bitta SessionFactory Hibernate uchun) yordamida ThreadLocal Session bu "parda orqasida") yoki JtaTransactionManager (JTA subsistemasi konteyneriga delegatsiya qilib) uchun Hibernate ilovalari uchun ishlatishingiz mumkin. Siz hatto o'z PlatformTransactionManager implementatsiyangizni ishlatishingiz mumkin. Nativ Hibernate tranzaktsiyalarini boshqarishdan JTA ga o'tish (masalan, ma'lum joylashuvlar uchun distribyutor tranzaktsiyalar talab qilinganida) faqat konfiguratsiya masalasidir. Tranzaktsiya ajratish kodi va ma'lumotlar kirish kodi ham o'zgarmay ishlashda davom etadi, chunki ular umumiy tranzaktsiyalar boshqarish interfeyslariga bog'langan.

Bir nechta Hibernate sessiya fabrikalari orasida distribyutor tranzaktsiyalar uchun JtaTransactionManager ni tranzaktsiya strategiyasi rolida birlashtirish mumkin, bir necha LocalSessionFactoryBean aniqlash orqali. Har bir DAO bitta aniq SessionFactory havolasini oladi, bu esa mos bin xususiyatiga uzatiladi. Agar barcha asosi ma'lumot manbalari JDBC bo 'lib, tranzaktsion va konteyner bo'lsa, biznes xizmat har qanday DAO va bir nechta sessiya fabrikalari orasida tranzaktsiyalarni ajratish qobiliyatiga ega bo'ladi, agar JtaTransactionManager strategiya sifatida ishlatilsa.

HibernateTransactionManager va JtaTransactionManager, agar siz EJB ni tranzaktsiyalarni boshlash uchun ishlatmasangiz, hech qanday tranzaktsiya menejeri qidirib ko'rmasdan Hibernate yordamida JVM darajasida keshni to'g'ri boshqarishni ta'minlash imkoniyatini beradi.

HibernateTransactionManager JDBC asosidagi Connection ni odatiy JDBC kirish kodi uchun Hibernate dan eksport qilish imkonini beradi ma'lum DataSource, bu esa aralash Hibernate va JDBC ma'lumotlar kirishiga ega yuqori darajadagi tranzaktsiyalar ajratish imkonini beradi, JTA holda, agar siz faqat bir ma'lumotlar bazasiga murojaat qilsangiz. Agar siz LocalSessionFactoryBean orqali DataSource orqali sozlangangan SessionFactory ni o'rnatgan bo'lsangiz, HibernateTransactionManager avtomatik ravishda Hibernate tranzaktsiyalarini JDBC tranzaktsiyalari sifatida ochadi. Yoki, HibernateTransactionManager klassidan dataSource xususiyati orqali, o'zingiz o'z belgilagan DataSource ni, tranzaktsiyalarni ochuvchi, aniqlashtirishingiz mumkin.

Konteyner tomonidan boshqariladigan resurslar va lokal ravishda belgilangan resurslarni taqqoslash

Siz JNDI dagi konteyner tomonidan boshqariladigan SessionFactory va lokal ravishda belgilangan orasida dastur kodini o'zgartirmasdan o'tish imkoniyatiga egasiz. Resursni konteynerda saqlash yoki lokal javobgarlikni saqlash, asosan ishlatilgan tranzaksiya strategiyasiga bog'liqdir. Spring tomonidan aniqlangan SessionFactory ni JNDI orqali qo'lda ro'yxatdan o'tkazish hech qanday afzallik bermaydi. SessionFactory'ni JCA konnektori orqali chiqarilishining yana bir afzalligi bor, Java EE server boshqaruv infrastrukturasi mavjud ekan, lekin bu aslida hech qanday ortiqcha qiymatga ega emas.

Spring'dagi tranzaktsiyalarni qo'llab-quvvatlash konteynerga bog'liq emas. Agar JTA strategiyasi emas, boshqa strategiyalar bilan sozlangan bo'lsa, tranzaktsiyalarni qo'llab-quvvatlash o'z-o'zidan yoki test muhitida ham ishlaydi. Bir manbali resurs uchun Spring'ning lokal tranzaktsion qo'llab-quvvatlashi JTA ning engil va to'liq quvvatli muqobil hisoblanadi, ayniqsa bitta ma'lumotlar bazasi bilan ishlayotgan odatiy tranzaktsiyalar holatida. Agar siz lokal state-less sessiya EJB binlaridan tranzaktsiyalarni boshqarishda foydalansangiz, EJB konteyneridan va JTA dan, bitta ma'lumotlar bazasiga murojaat qilishingiz shart emas va faqat state-less sessiya binlardan foydalansangiz ham, siz konteyner boshqariladigan tranzaktsiyalar orqali deklarativ tranzaktsiyalar mavjud bo'lasiz. JTA ni dasturiy ravishda ishlatish shuningdek Java EE muhitini talab qiladi. JTA JNDI dagi DataSource kabi ko'paytirishlarni o'z ichiga oladi. JTA tomonidan boshqariladigan Springga aloqador bo'lmagan Hibernate tranzaktsiyalari uchun Hibernate'dan JCA konnektori yoki Hibernate'dan tranzaktsional kod bilan TransactionManagerLookup bilan qo'shimcha konfiguratsiya qilish kerak, bu esa JVM darajasida keshga mos kelish uchun mo'ljallangan.

Spring tomonidan boshqariladigan tranzaktsiyalar, agar ular faqat bitta ma'lumotlar bazasiga murojaat qilinsa, Hibernate dan lokal ravishda belgilangan SessionFactory bilan ham yaxshi ishlaydi, xuddi JDBC dan lokal DataSource bilan. Shunday qilib, Spring'ning JTA tranzaktsion strategiyasini faqat distribyutor tranzaktsiyalar uchun talablar mavjud bo'lganda ishlatish kerak. JCA-konnektori konteynerlarga o'ziga xos o'rnatish bosqichlarini va (aniq o'zida) JCA ni qo'llab-quvvatlash imkoniyatlarini talab qiladi. Bunday konfiguratsiya, resurslarning lokal aniqlanishi va Spring tomonidan boshqariladigan tranzaktsiyalar, bitta veb-ilovani muhitga qo'llashdan ko'proq vaqtda amalga oshiriladi. Agar masalan, WebLogic Express ni qo'llasangiz, bu JCA ni taqdim etmaydi. Lokal resurslar va bitta ma'lumotlar bazasini o'z ichiga olgan tranzaktsiyalar bilan Spring dasturi har qanday Java EE veb-konteynerida (JTA, JCA yoki EJB ishlatmay) ishlaydi, masalan, Tomcat, Resin yoki hatto oddiy Jetty. Bundan tashqari, bunday o'rtachalikni osonlik bilan stoldagi dasturlarda yoki test garnituralarida qayta ishlatish mumkin.

Umuman olganda, agar siz EJB binlaridan foydalanmaydigan bo'lsangiz, Spring'dan HibernateTransactionManager yoki JtaTransactionManager ni ishlatish va lokal SessionFactory ni sozlashni tayinlang. Siz barcha afzalliklarni, jumladan to'g'ri tranzaktsion JVM darajasida kesh va distribyutor tranzaktsiyalarni foydalanish imkoniyatiga ega bo'lasiz, konteynerlarni joylashtirish bilan bog'liq noqulayliklarsiz. Hibernate'dan JCA konnektori orqali JNDI ro'yxatiga olish faqatgina EJB binlari bilan birlashganda foydali bo'ladi.

Hibernate ishlatishda ilova serverining noto'g'ri ogohlantirishlari

Bazining juda qat'iy amalga oshirilishi bilan ba'zi JTA muhitlarida XADataSource (hozirda ba'zi WebLogic Server va WebSphere versiyalari), agar Hibernate ushbu muhit uchun JTA tranzaktsiyalar menejerini hisobga olmagan holda sozlangan bo'lsa, ilova serveri jurnallarida yolg'on ogohlantirishlar yoki istisnolar paydo bo'lishi mumkin. Ushbu ogohlantirishlar yoki istisnolar, ushbu tranzaktsiya endi faol emasligi sababli, dataga kirish endi amal qilmasligi mumkinligini bildiradi. Quyidagi WebLogic dan haqiqiy istisnolar misol sifatida keltirilgan:

java.sql.SQLException: The transaction is no longer active - status: 'Committed'. No
further JDBC access is allowed within this transaction.

Boshqa keng tarqalgan muammo, agar Hibernate sessiyalari (va ehtimol asosiy JDBC bağlantısı) to'g'ri yopilmagan bo'lsa, JTA tranzaktsiyalaridan so'ng ulanishning oqib chiqishi hisoblanadi.

Bu muammolar Hibernate'ni JTA tranzaktsiyalar menejeri bilan mos kelishiga asoslangan holda hal qilinishi mumkin (Spring bilan birgalikda). Buning ikkita usuli mavjud:

  • Spring'dan JtaTransactionManager ni Hibernate sozlashiga qo'shing. Eng oddiy usul, LocalSessionFactoryBean uchun jtaTransactionManager xususiyatiga havola berishdir (bo'limga qarang "Hibernate tranzaktsiyalar sozlamalari"). Shunda Spring mos JTA strategiyalarini Hibernate uchun mavjud qiladi.

  • Shuningdek, LocalSessionFactoryBean ning Hibernate bilan bog'liq sozlamalarini, ayniqsa "hibernate.transaction.coordinator_class", "hibernate.connection.handling_mode" va ehtimol "hibernate.transaction.jta.platform" ni "hibernateProperties" da aniq o'rnatish mumkin (ushbu sozlamalar uchun batafsil xabarlar Hibernate qo'llanmasida mavjud).

Bu bo'limning qolgan qismida, Hibernate'ning JTA dan PlatformTransactionManager bilan moslashganligiga va moslashmaganligiga qarab, sodir bo'ladigan hodisalar ketma-ketligi keltirilgan.

Agar Hibernate JTA tranzaktsiyalar menejerini hisobga olmasdan sozlangan bo'lsa, JTA tranzaktsiyasi tasdiqlanganda quyidagi voqealar sodir bo'ladi:

  • JTA tranzaktsiyasi tasdiqlanadi.

  • Spring'dan JtaTransactionManager JTA tranzaktsiyasi bilan sinxronlashtiriladi, shuning uchun u JTA tranzaktsiyalar menejeri orqali afterCompletion callbeki orqali chaqiriladi.

  • Boshqa harakatlar orasida, bu sinxronlash Spring tomonidan Hibernate ga afterTransactionCompletion callbeki orqali qaytarish sabab bo'ladi (Hibernate keshini tozalash uchun ishlatiladi), shun dan keyin Hibernate sessiyasini close() ni chaqirish orqali aniq yopilishiga olib keladi, bu esa Hibernate JDBC ulanishni close() qilishga harakat qiladi.

  • Ba'zi muhitlarda, bu Connection.close() chaqirishi ogohlantirish yoki xato sabab bo'ladi, chunki ilova serveri endi Connectionni ishlatishga yaroqli deb hisoblamaydi, chunki tranzaktsiya allaqachon tasdiqlangan.

Agar Hibernate JTA tranzaktsiyalar menejeri hisobga olgan holda sozlangan bo'lsa, JTA tranzaktsiyasi tasdiqlanganda quyidagi hodisalar sodir bo'ladi:

  • JTA tranzaktsiyasi tasdiqlanishga tayyor.

  • Spring'dan JtaTransactionManager JTA tranzaktsiyasi bilan sinxronlashtiriladi, shuning uchun tranzaktsiya JTA tranzaktsiyalar menejeri orqali beforeCompletion callbeki orqali chaqiriladi.

  • Spring Hibernate'ning o'zi JTA tranzaktsiyasi bilan sinxronlashganligini hisobga oladi va oldingi ssenariyga qaraganda boshqacha ishlay boshlaydi. Xususan, u Hibernate'dan resurslarni boshqarish bilan tranzaktsion moslashuvni amalga oshiradi.

  • JTA tranzaktsiyasi tasdiqlanadi.

  • Hibernate JTA tranzaktsiyasi bilan sinxronlashganligi sababli, tranzaktsiya JTA tranzaktsiyalar menejeri orqali afterCompletion callbeki orqali chaqiriladi va o'z keshini to'g'ri tozalashi mumkin.

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION