异步查询在Spring Data JPA项目中无法正常工作

时间:2017-07-20 01:53:14

标签: java jpa asynchronous spring-data spring-data-jpa

在参加了@CopusBowersox的针对Java开发人员的Spring Data的Infinite Skills课程之后,唯一似乎没有像宣传的那样工作的部分是Async方法。请注意,在课程开始时,他介绍了xml和Java配置,但他在整个课程的其余部分继续使用xml配置,而我继续使用Java配置进行每个练习,并且能够获得所有其他部分工作。一个小的区别是我使用IntelliJ IDEA而不是STS,正如他在整个课程中使用的那样。

如果有任何熟悉Spring Data异步查询或其课程(https://www.safaribooksonline.com/library/view/spring-data-for/9781771375924/video241705.html)的人对可能遗漏的内容有所了解,请告知我们。

以下是相关位:

/ * Application.java * /

@EnableAsync
public class Application {

public static void main(String[] args) throws ParseException {

    try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
            DataConfiguration.class)) {
        BookRepository repository = context.getBean(BookRepository.class);

        // TODO: Make method Async
        for (long x = 0; x < 4; x++) {
            repository.findByIds(x);
        }
    }
}

}

/ * BaseRepository.java * /

@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {

    @Override
    @Async("executor")
    List<T> findByIds(ID... ids);
}

/ * ExtendedRepositoryImpl.java * /

public class ExtendedRepositoryImpl<T, ID extends Serializable>
        extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {
    private JpaEntityInformation<T, ?> entityInformation;
    private final EntityManager entityManager;

    public ExtendedRepositoryImpl(
            JpaEntityInformation<T, ?> entityInformation,
            EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityInformation = entityInformation;
        this.entityManager = entityManager;
    }

    @Override
    public List<T> findByIds(ID... ids) {
        Query query = this.entityManager.createQuery("select e from " + this.entityInformation.getEntityName()
        + " e where e." + this.entityInformation.getIdAttribute().getName() + " in :ids");
        query.setParameter("ids", Arrays.asList(ids));

        long wait = new Random().nextInt(10000-1) +1;
        System.out.println(wait);

        try {
            Thread.sleep(wait);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Executing query for ID: " + Arrays.toString(ids));

        return (List<T>) query.getResultList();
    }
}

/ * DataConfiguration.java(又名AppConfig.java)* /

@EnableJpaRepositories(
            basePackages = {"com.infiniteskills.springdata.async"},
            repositoryBaseClass = com.infiniteskills.springdata.async.data.repository.ExtendedRepositoryImpl.class,
            repositoryImplementationPostfix = "CustomImpl")
    @EnableJpaAuditing(auditorAwareRef = "customAuditorAware")
    @EnableAsync
    @EnableTransactionManagement
    @ComponentScan("com.infiniteskills.springdata.async")
    @Configuration
    public class DataConfiguration implements AsyncConfigurer {
        @Bean
        public CustomAuditorAware customAuditorAware() {
            return new CustomAuditorAware();
        }

        @Bean
        public DataSource dataSource() {
            EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
            return builder.setType(EmbeddedDatabaseType.H2).build();
        }

        @Bean
        public EntityManagerFactory entityManagerFactory() {
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            // Generate tables in database
            vendorAdapter.setGenerateDdl(true);

            Properties jpaProperties = new Properties();
            jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
            //jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
            //jpaProperties.put("hibernate.connection.driver_class", "org.h2.Driver");

            // After DDL has been run, run init script to populate table with data.
            jpaProperties.put("hibernate.hbm2ddl.import_files", "init.sql");

            // Entity Manager Factory Bean
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource());
            entityManagerFactoryBean.setPackagesToScan("com.infiniteskills.springdata.async");
            entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            entityManagerFactoryBean.setJpaProperties(jpaProperties);
            entityManagerFactoryBean.afterPropertiesSet();
            return entityManagerFactoryBean.getObject();
        }

        @Bean
        public PlatformTransactionManager transactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(entityManagerFactory());
            return transactionManager;
        }

        @Override
        @Bean(name = "executor")
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(10);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(100);
            executor.setThreadNamePrefix("executor-");
            executor.initialize();
            return executor;
        }

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

3 个答案:

答案 0 :(得分:1)

该方法必须具有返回类型voidFuture才能被称为异步。

您可以在此处的文档中阅读:https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async

答案 1 :(得分:1)

@EnableAsync用于任何@Configuration类。

来自docs

  

要与@Configuration类一起使用,如下所示,为整个Spring应用程序上下文启用注释驱动的异步处理:

使用Application注释您的@Configuration课程。

希望这有帮助。

答案 2 :(得分:0)

由于我在练习中一直使用Java配置,因此我最初不确定是否使用了与演示的xml配置等效的所有正确注释。 IntelliJ IDEA可以提供与STS不同的代码建议......

无论如何,课程的Spring Data Async Queries部分(https://www.safaribooksonline.com/library/view/spring-data-for/9781771375924/video241705.html)让我质疑我的理智。

基本上,结果是我的Application.java类:

public class Application {

public static void main(String[] args) throws ParseException {

    try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
            DataConfiguration.class)) {
        BookRepository repository = context.getBean(BookRepository.class);

        // TODO: Make method Async
        for (long x = 0; x < 4; x++) {
            repository.findByIds(x);
        }
    }
}

}

应该没有try-with-resources语法,而是看起来像这样:

public class Application {

    public static void main(String[] args) throws ParseException {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
            DataConfiguration.class)
        BookRepository repository = context.getBean(BookRepository.class;

        for (long x = 0; x < 4; x++) {
            repository.findByIds(x);
        }
    }    
}