2014-07-23 18 views
8

Spring Data ve Hibernate kullanan basit bir Tomcat webapp yapıyorum. Çok fazla iş yapan bir bitiş noktası var, bu yüzden işi bir arka plan iş parçacığına boşaltmak istiyorum, böylece iş yapılırken web isteği 10+ dakika boyunca askıda kalmaz. Yani bir bileşen scan'd paketinde yeni bir hizmet yazdı: Yay Verilerini ve Hazırda Bekletme'yi kullanırken arka plan iş parçacığını düzgün bir şekilde nasıl yaparım?

@Service 
public class BackgroundJobService { 
    @Autowired 
    private ThreadPoolTaskExecutor threadPoolTaskExecutor; 

    public void startJob(Runnable runnable) { 
     threadPoolTaskExecutor.execute(runnable); 
    } 
} 

Sonra baharda yapılandırılmış ThreadPoolTaskExecutor var:

<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
    <property name="corePoolSize" value="5" /> 
    <property name="maxPoolSize" value="10" /> 
    <property name="queueCapacity" value="25" /> 
</bean> 

Bu, tüm çalışma harika. Ancak, sorun Hibernate'den geliyor. Koşuculuğumun içinde sadece yarım iş var.

MyObject myObject = myObjectRepository.findOne() 
myObject.setSomething("something"); 
myObjectRepository.save(myObject); 

Ama tembel yüklenen alanları varsa, başarısız: Yapabileceğim

MyObject myObject = myObjectRepository.findOne() 
List<Lazy> lazies = myObject.getLazies(); 
for(Lazy lazy : lazies) { // Exception 
    ... 
} 

alıyorum aşağıdaki hata:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.stackoverflow.MyObject.lazies, could not initialize proxy - no Session 

yüzden (bana öyle Hibernate görünüyor newbie) yeni iş parçacığının bu ev yapımı iş parçacığı üzerinde bir oturumu olmadığını, ancak Spring Data HTTP İstek iş parçacıkları için otomatik olarak yeni oturumlar oluşturuyor.

  • Oturumun içinden yeni bir oturum başlatmak için bir yol var mı?
  • Ya benim için bunu yapmak için iş parçacığı havuzu anlamanın bir yolu?
  • Bu tür işleri yapmak için standart uygulama nedir?

Biraz bir @Transactional yöntemi içinde her şeyi yaparak kendisine geçici bir çözüm mümkün oldum ama bu beni işe yöntemleri kullanmak izin vermez gibi çabuk, bu çok iyi bir çözüm değil öğreniyorum sadece web istekleri için iyi.

Teşekkürler. ne olur

cevap

0

muhtemelen kod DAO parçası üzerinde işlem varsa ve Bahar işlem kapanırken oturumu kapatıyor vardır.

Sen tek bir işlem içine tüm iş mantığını sıkmak gerekir.

Sen koduna SessionFactory enjekte ve SessionFactory.openSession() yöntemi kullanabilirsiniz.
Sorun şu ki, işlemlerinizi yönetmek zorunda kalacaksınız.

+0

Sorun, çalıştığı sırada işin durumunu güncelleyebilmek istiyorum. Bu yüzden hepsini tek bir işlemde sarsam, durum en fazla dışa aktarma işlemine kadar güncellenmez. Burada bir şey kaçırmadığım sürece ... ki bu tamamen mümkün :) – Joel

+0

Runnable uygulama sınıfınızı ve belki ObjectRepository'nizi gösterebilir misiniz? Ayrıca, durum güncellemelerini nasıl ve nerede yayınlamayı planladığınızı merak ediyorum. http tabanlı web uygulamaları ile bu kadar açık değil. – alobodzk

+0

Özellikle işlem durumunu güncellemek için: iç içe geçmiş bir işlem kullanın. JPA sağlayıcınızın bunları desteklediğinden emin olun. – Virmundi

19

Bahar ile kendi vasisi gerekmez. Basit bir açıklama @Async sizin için iş yapacak. Sadece servisinizde heavyMethod numaranıza açıklama ekleyerek geçersiz veya Future nesnesine geri dönün ve bir arka plan iş parçacığı elde edersiniz. İstek havuzu yürütücüsünde eşzamansız bir iş parçacığı oluşturacağından ve "istek alıcıları" nızdan çıkabileceğinden, denetleyici düzeyinde async açıklamasını kullanmamaya çalışacağım. Bir oturumu yok yeni iplikten şüpheli olarak

Tembel hariç sorun geliyor. Bu sorunu önlemek için async yönteminiz tüm işi ele almalıdır. Önceden yüklenmiş varlıkları parametre olarak sağlama. Servis bir EntityManager kullanabilir ve ayrıca işlem olabilir.

Kendim için @Async ve @Transactional birleştirme, bu nedenle hizmeti her iki şekilde de çalıştırabilirim. Hizmetin etrafındaki async sarmalayıcıyı yaratıyorum ve gerektiğinde bunun yerine kullanıyorum. (Bu durum, örneğin test basitleştirir)

@Service 
public class AsyncService { 

    @Autowired 
    private Service service; 

    @Async 
    public void doAsync(int entityId) { 
     service.doHeavy(entityId); 
    } 
} 

@Service 
public class Service { 

    @PersistenceContext 
    private EntityManager em; 

    @Transactional 
    public void doHeavy(int entityId) { 
     // some long running work 
    } 
} 
+0

Bu teknik, eski Spring Roo 1.3.x uygulamam için mükemmel bir şekilde çalıştı. Eski uygulamayı geliştirmek zorunda kaldım ve bir çekicilik gibi çalıştı. Teşekkür ederim!! – sunitkatkar

-1

Yöntem # 1: JPA varlık Yöneticisi

arka thread: işletme yöneticisi enjekte veya Bahar bağlamdan almak ya da referans olarak geçmek:

@PersistenceContext 
private EntityManager entityManager;  

EntityManager em = entityManager.getEntityManagerFactory().createEntityManager(); 
:

Sonra bir ortak kullanmaktan kaçınmak için, yeni bir varlık yöneticisi oluşturmak , JdbcTemplate

Eğer düşük seviyeli değişiklikleri ihtiyaç halinde

veya görevin yeterince basittir:

Şimdi hareketi başlatmak ve kullanımı vb Bahar DAO Repository'ı, JPA,

private void save(EntityManager em) { 

    try 
    {   
     em.getTransaction().begin();     

     <your database changes> 

     em.getTransaction().commit();       
    } 
    catch(Throwable th) { 
     em.getTransaction().rollback(); 
     throw th; 
    }   
} 

Yöntem 2. edebilirsiniz senin yönteminde bir yere sonra

@Autowired 
private JdbcTemplate jdbcTemplate; 

ve: el JDBC ve sorgu ile bunu yapabilir

jdbcTemplate.update("update task set `status`=? where id = ?", task.getStatus(), task.getId()); 

Yan not: JTA kullanın veya JpaTransactionManager itimat sürece uzak @Transactional uzak durmaya öneriyoruz.

+0

Bu doğru değil! @Transactional, JTA'ya ihtiyaç duymaz. Bir işlem yöneticisi ayrıca işlemleri işlemek için EntityManager'ı kullanan bir org.springframework.orm.jpa.JpaTransactionManager olabilir! –

+0

Geri bildiriminiz için teşekkür ederiz. @Transactional ile ilgili öneriyi şimdi daha spesifik yaptım. Arka plan iş parçacığında sorunun nasıl işleneceği konusunda çalışma önerilerinin içeriği ve doğruluğunu etkilemez. – alexzender

+0

Hala kabul etmiyorum çünkü kendi işlemlerinizi ele almak zahmetli olabilir. Örneğinizde em.getTransaction(). Rollback() öğesini çağırırken; işlem inaktif olabilir. Bunu kontrol etmelisin! –

İlgili konular