Spring 引导 JPA 存储库传递给另一个线程不工作

Spring boot JPA repository passed to another thread not working

我有一个自动装配的 jpa 存储库对象在工作。但是,我需要使用它从多个线程向数据库中添加行。
虽然,将它传递给另一个线程后,它失败了。 代码结构

@SpringBootApplication(exclude = HealthcheckConfig.class)
public class Application implements CommandLineRunner {

    @Autowired
    private DBRepository dbRepository;

    @Autowired
    private AppConfig appConfig;

    private ExecutorService executors = Executors.newFixedThreadPool(3);

    Application() {
    }

    @Override
    public void run(final String... args) {

        final DBSchemaObject temp = new Application("testdb", "testfield");
        dbRepository.save(temp); // This WORKs!!!
       
        for (FileStatus fileStatus: fileStatuses) {
            executors.execute(new ThreadSafeClass(dbRepository));
        }
    }

    public static void main(final String[] args) {
        new SpringApplicationBuilder(Application.class)
                .web(WebApplicationType.NONE)
                .run(args)
                .close();
    }
}

但是,从线程安全 class 执行 dbRepository.save(),我收到错误 原因:java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@41330d4f has been closed already

详细消息:Error creating bean with name 'spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties': Could not bind properties to 'DataSourceProperties' : prefix=spring.datasource, ignoreInvalidFields=false, ignoreUnknownFields=true

堆栈跟踪:

{StackTraceElement@14839} "org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)"
{StackTraceElement@14840} "org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)"
{StackTraceElement@14841} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)"
{StackTraceElement@14842} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)"
{StackTraceElement@14843} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)"
{StackTraceElement@14844} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)"
{StackTraceElement@14845} "org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=12=](AbstractBeanFactory.java:335)"
{StackTraceElement@14846} "org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)"
{StackTraceElement@14847} "org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)"
{StackTraceElement@14848} "org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)"
{StackTraceElement@14849} "org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:410)"
{StackTraceElement@14850} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334)"
{StackTraceElement@14851} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)"
{StackTraceElement@14852} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)"
{StackTraceElement@14853} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)"
{StackTraceElement@14854} "org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=12=](AbstractBeanFactory.java:335)"
{StackTraceElement@14855} "org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)"
{StackTraceElement@14856} "org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)"
{StackTraceElement@14857} "org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)"
{StackTraceElement@14858} "org.springframework.beans.factory.support.DefaultListableBeanFactory.orderedStream(DefaultListableBeanFactory.java:481)"
{StackTraceElement@14859} "org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:167)"
{StackTraceElement@14860} "org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:149)"
{StackTraceElement@14861} "org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)"
{StackTraceElement@14862} "org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)"
{StackTraceElement@14863} "org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)"
{StackTraceElement@14864} "org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)"
{StackTraceElement@14865} "org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)"
{StackTraceElement@14866} "org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)"
{StackTraceElement@14867} "com.sun.proxy.$Proxy99.save(Unknown Source)"
{StackTraceElement@14868} "com.xxxx.run(Application.java:109)"
{StackTraceElement@14869} "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)"
{StackTraceElement@14870} "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)"
{StackTraceElement@14871} "java.lang.Thread.run(Thread.java:748)"

如何跨多个线程使用 spring 引导存储库对象?

问题是您的 run() 方法只是安排要执行的任务,而不是等待它们完成。这是正在发生的事情:

  1. new SpringApplicationBuilder(Application.class) 您正在使用命令行创建一个新的应用程序上下文 运行ner Application
  2. .run(args) 然后你 initialize and execute 你的应用上下文的 run() 方法
  3. run()方法调度要执行的任务并立即存在:
 public void run(final String... args) {
        for (FileStatus fileStatus: fileStatuses) {
            executors.execute(new ThreadSafeClass(dbRepository));
        }
    }
  1. 因为 run() 终止,spring 假定应用程序已经完成并调用 .close(); 因此 closing 应用程序上下文并使其无法使用任何 spring 功能,例如存储库。

  2. 计划的任务已经执行,但是上下文已经关闭,因此它们失败并抛出异常。

解决方法是等待任务完成后再退出运行方法。由于你的例子太少了,这只是一个例子。或者,您可以使用其他方法等待 CountDownLatch 等任务完成,而不必关闭线程池:

for (FileStatus fileStatus: fileStatuses) {
    executors.execute(new ThreadSafeClass(dbRepository));
}
executors.shutdown(); // prevents the executor from accepting any new tasks
executors.awaitTermination(); // wait for the tasks to finish

ExecutorService::shutdown javadoc

ExecutorService::awaitTermination javadoc