Note that there are some explanatory texts on larger screens.

plurals
  1. POSpring Data JPA repositories, transactions and eventing in Spring
    primarykey
    data
    text
    <p>The amount of grey hair has dramatically increased in last couple of days while trying to resolve the following problem. I'm using Spring Data JPA repositories in custom event listeners that utilises simple Spring 3.2 eventing mechanism. The problem I'm having is that if <code>ListenerA</code> creates an entity and calls <code>assetRepository.save(entity)</code> or <code>assetRepository.saveAndFlash(entity)</code> the subsequent calls to retrieve this same entity from another listener fails. The cause seems to be that the <code>ListenerB</code> can not find the original entity in the database, it seem to be still in Hibernate's cache. The trigger for ListenerB to lock up the entity is an event fired as a result of a runnable task execution from a thread pool. Here is my configuration:</p> <pre><code>&lt;bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt; &lt;property name="dataSource" ref="dataSource" /&gt; &lt;property name="persistenceUnitName" value="spring-jpa" /&gt; &lt;property name="jpaVendorAdapter"&gt; &lt;bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"&gt; &lt;property name="generateDdl" value="false" /&gt; &lt;property name="database" value="#{appProps.database}" /&gt; &lt;/bean&gt; &lt;/property&gt; &lt;property name="jpaProperties"&gt; &lt;props&gt; &lt;prop key="hibernate.dialect"&gt;org.hibernate.dialect.Oracle10gDialect&lt;/prop&gt; &lt;prop key="hibernate.hbm2ddl.auto"&gt;#{appProps['hibernate.hbm2ddl.auto']}&lt;/prop&gt; &lt;prop key="hibernate.show_sql"&gt;#{appProps['hibernate.show_sql']}&lt;/prop&gt; &lt;prop key="hibernate.format_sql"&gt;#{appProps['hibernate.format_sql']}&lt;/prop&gt; &lt;prop key="hibernate.search.default.directory_provider"&gt;org.hibernate.search.store.impl.FSDirectoryProvider&lt;/prop&gt; &lt;prop key="hibernate.search.default.indexBase"&gt;#{appProps.indexLocation}&lt;/prop&gt; &lt;prop key="hibernate.search.lucene_version"&gt;#{appProps['hibernate.search.lucene_version']}&lt;/prop&gt; &lt;/props&gt; &lt;/property&gt; &lt;/bean&gt; &lt;tx:annotation-driven transaction-manager="transactionManager" /&gt; &lt;bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt; &lt;property name="entityManagerFactory" ref="entityManagerFactory" /&gt; &lt;property name="jpaDialect"&gt; &lt;bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /&gt; &lt;/property&gt; &lt;/bean&gt; </code></pre> <p>I'm omitting the <code>dataSource</code> configuration which is an instance of <code>ComboPooledDataSource</code> that defines connection to Oracle database. As a side note, component scanning is used and the project is Spring MVC. Now Java classes.</p> <p><strong>ListenerA</strong></p> <pre><code>@Sevice public class ListenerA implements ApplicationListener&lt;FileUploadedEvent&gt; { @Autowired private AssetRepository assetRepository; @Autowired private ExecutorService executor; // Triggers runnable task on a Job in Spring's TaskExecutor @Override @Transactional public void onApplicationEvent(FileUploadedEvent event) { Asset target = event.getTarget(); Job job = new Job(target); assetRepository.save(job); executor.execute(job); } </code></pre> <p><strong>ListenerB</strong></p> <pre><code>@Sevice public class ListenerB implements ApplicationListener&lt;JobStartedEvent&gt; { @Autowired private AssetRepository assetRepository; @Override @Transactional public void onApplicationEvent(JobStartedEvent event) { String id = event.getJobId(); Job job = assetRepository.findOne(id); // at this point we can not find the job, returns null job.setStartTime(new DateTime()); job.setStatus(Status.PROCESSING); assetRepository.save(job); } </code></pre> <p><code>JobStartedEvent</code> is fired from a runnable task within <code>TaskExecutor</code>. What I'm doing wrong here? I have tried to use custom event publisher that is transaction aware, but that doesn't seem to solve the problem. I have also tried to wire appropriate service instead of data repository and remove <code>@Transactional</code> annotations from listeners, which also have failed. Any reasonable suggestions of how to solve the problem would be welcome.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload