2015-03-25 2 views
3

Я использую Open Session-In-View-модель транзакций для моего REST API, как это:@Async убивает Hibernate транзакции

@Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     sessionFactory.getCurrentSession().beginTransaction(); 
     chain.doFilter(request, response); 
     sessionFactory.getCurrentSession().getTransaction().commit(); 
} 

Эта работа просто отлично. Я хотел добавить способности @Async. Так что я создал:

@Configuration 
@EnableAsync 
public class AsyncConfig implements AsyncConfigurer { 

    @Override 
    @Bean(destroyMethod="shutdown") 
    public Executor getAsyncExecutor() { 
     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
     executor.setCorePoolSize(18); 
     executor.setMaxPoolSize(18); 
     executor.initialize(); 
     executor.setDaemon(true); 
     executor.setWaitForTasksToCompleteOnShutdown(false); 
     return executor; 
    } 

    @Override 
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 
     return new SimpleAsyncUncaughtExceptionHandler(); 
    } 
} 

и:

@Component 
public class AsyncMarketCaller { 

    @Inject 
    MarketManagerFactory marketManagerFactory; 

    @Async 
    public Future<List<Product>> getProducts(){ 

     MarketManager productManager = marketManagerFactory.obtainMarketManager(market); 
     result = productManager.getProducts(); 
     .... 
    } 
} 

делает менеджер по продукту вызова другого @Service

@Service 
public class DefaultIdentifierManager implements IdentifierManager{ 
    @Inject 
    UpcEanDAO upcEanDAO; 

     @Override 
    public String getTitleForIdentifier(String identifier){ 
     UpcEan upcEan = upcEanDAO.find(identifier); 
    } 
} 

Однако для upcEanDAO.find(identifier) я получаю исключение:

Caused by: org.hibernate.HibernateException: get is not valid without active transaction 

До I добавил @Async возможность совершать асинхронные вызовы до getProducts(), он работал нормально, поэтому я предполагаю, что @Async убивает транзакцию, которую я открыл с помощью Hibernate.

Я попытался добавить на основании другого ответа здесь, @Transactional к методу, аннотированному с @Async, но это не поможет.

Есть идеи?

EDITED

Я редактировал код так

@Component 
public class AsyncMarketCaller { 

    @Inject 
    AsyncMarketService asyncMarketService; 

    @Async 
    public Future<List<Product>> getProducts(){ 
     asyncMarketService.getProducts(); 
    } 
} 

и

@Service 
public class AsyncMarketService { 

    @Inject 
    MarketManagerFactory marketManagerFactory; 

    @Transactional 
    public Future<List<Product>> getProducts() 
    .... 
} 

} 

Я вижу в журнале

50689 DEBUG [localhost-startStop-1] org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'AsyncMarketService.getProducts' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 

но это не помогает. Обратите внимание, что мой метод AsyncMarketService.getProducts не вызывает непосредственно БД, он вызывает другие методы, и только один из них сделает вызов.

Я также добавил выше того, что на самом деле сделать вызов к БД: @Transactional

49992 DEBUG [localhost-startStop-1] org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'DefaultIdentifierManager.getTitleForIdentifier' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ' '

+0

Поскольку ваша транзакция поручена через фильтр, не может быть сделкой на месте, когда вам это нужно. – Hannes

+0

@ Ханнес - он работал до того, как я добавил Async - который является частью вызова фильтра – Dejell

ответ

3

Hibernate транзакции работают на ThreadLocal основе.

При использовании другой темы с @Async транзакций не будет.

Вы можете достичь этой функциональности, используя метод async, вызывающий другой компонент, который аннотируется @Transactional.

Здесь я объясняю этот подход немного больше: How do I properly do a background thread when using Spring Data and Hibernate?

+0

Я пробовал ваше решение, как вы можете видеть в отредактированном ответе. но никакой помощи. Что ты предлагаешь? – Dejell

+0

вызовы выполняются следующим образом: AsyncServices-> HelpService-> MarketService-> IdentifierService-> DAOLayer для извлечения элемента. У меня @transactional только выше метода HelpService – Dejell

+0

вы можете попробовать его с возвращаемыми значениями 'void'? Я не уверен, что это работает с Futures –

Смежные вопросы