ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring中的Spring Data JPA存储库,事务和事件

2019-11-23 07:20:16  阅读:364  来源: 互联网

标签:spring-data-jpa event-handling hibernate spring spring-mvc


在过去的几天中,试图解决以下问题的白发数量急剧增加.我在利用简单Spring 3.2事件机制的自定义事件侦听器中使用Spring Data JPA存储库.我遇到的问题是,如果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类.

听众A

@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);
}

侦听器B

@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);
}

从TaskExecutor中的可运行任务触发JobStartedEvent.
我在这里做错了什么?我尝试使用具有事务意识的自定义事件发布者,但这似乎无法解决问题.我还尝试连接适当的服务而不是数据存储库,并从侦听器中删除@Transactional批注,这也失败了.任何有关解决问题的合理建议都将受到欢迎.

解决方法:

由于@Kresimir Nesek的提示,我设法解决了这个问题.因此,解决方案是用适当的服务替换Spring Data存储库.
这是修改后的类.

听众A

@Sevice
public class ListenerA implements ApplicationListener<FileUploadedEvent> {

    @Autowired
    private JobService service;

    @Autowired
    private ExecutorService executor; // Triggers runnable task on a Job in Spring's TaskExecutor

    @Override
    public void onApplicationEvent(FileUploadedEvent event) {

    Job job = service.initJobForExecution(event.getTarget());

    executor.execute(job);
    }
 }

在JobService方法中,必须使用@Transactional(propagation = Propagation.REQUIRES_NEW)注释initJobForExecution(资产目标).

听众B

@Sevice
public class ListenerB implements ApplicationListener<JobStartedEvent> {

@Autowired
private JobService service;


@Override
public void onApplicationEvent(JobStartedEvent event) {
    service.updateStatus(event.getJobId(), Status.PROCESSING); 
 }
}

标签:spring-data-jpa,event-handling,hibernate,spring,spring-mvc
来源: https://codeday.me/bug/20191123/2065862.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有