ListenerA
创建实体并调用assetRepository.save(entity)
或assetRepository.saveAndFlash(entity)
,则从另一个侦听器检索此相同实体的后续调用将失败。原因似乎是ListenerB
无法在数据库中找到原始实体,它似乎仍然在Hibernate的缓存中。
触发ListenerB锁定实体的是作为线程池中可运行任务执行结果而触发的事件。
我的配置如下:<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="spring-jpa" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="database" value="#{appProps.database}" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">#{appProps['hibernate.hbm2ddl.auto']}</prop>
<prop key="hibernate.show_sql">#{appProps['hibernate.show_sql']}</prop>
<prop key="hibernate.format_sql">#{appProps['hibernate.format_sql']}</prop>
<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.impl.FSDirectoryProvider</prop>
<prop key="hibernate.search.default.indexBase">#{appProps.indexLocation}</prop>
<prop key="hibernate.search.lucene_version">#{appProps['hibernate.search.lucene_version']}</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
我忽略了
dataSource
配置,它是一个ComboPooledDataSource
实例,用于定义与Oracle数据库的连接。额外说明一下,组件扫描被使用,并且该项目是Spring MVC。现在开始讲Java类。 ListenerA
@Sevice
public class ListenerA implements ApplicationListener<FileUploadedEvent> {
@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);
}
ListenerB
@Sevice
public class ListenerB implements ApplicationListener<JobStartedEvent> {
@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);
}
JobStartedEvent
是从 TaskExecutor
中的可运行任务触发的事件。
我在这里做错了什么?我尝试使用自定义事件发布程序,该程序具有事务感知能力,但似乎并没有解决问题。我还尝试将适当的服务连接而不是数据存储库,并从侦听器中删除 @Transactional
注释,但也失败了。欢迎提出任何合理的建议以解决问题。
@Transactional(propagation=Propagation.REQUIRES_NEW)
注释初始化方法(其中首先创建和保存Job对象)。我不确定这是否是解决此问题的正确方法。为什么我不能在我的监听器中使用存储库? - pilot