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()
方法只是安排要执行的任务,而不是等待它们完成。这是正在发生的事情:
new SpringApplicationBuilder(Application.class)
您正在使用命令行创建一个新的应用程序上下文 运行ner Application
.run(args)
然后你 initialize and execute 你的应用上下文的 run()
方法
run()
方法调度要执行的任务并立即存在:
public void run(final String... args) {
for (FileStatus fileStatus: fileStatuses) {
executors.execute(new ThreadSafeClass(dbRepository));
}
}
因为 run()
终止,spring 假定应用程序已经完成并调用 .close();
因此 closing 应用程序上下文并使其无法使用任何 spring 功能,例如存储库。
计划的任务已经执行,但是上下文已经关闭,因此它们失败并抛出异常。
解决方法是等待任务完成后再退出运行方法。由于你的例子太少了,这只是一个例子。或者,您可以使用其他方法等待 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
我有一个自动装配的 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()
方法只是安排要执行的任务,而不是等待它们完成。这是正在发生的事情:
new SpringApplicationBuilder(Application.class)
您正在使用命令行创建一个新的应用程序上下文 运行nerApplication
.run(args)
然后你 initialize and execute 你的应用上下文的run()
方法run()
方法调度要执行的任务并立即存在:
public void run(final String... args) {
for (FileStatus fileStatus: fileStatuses) {
executors.execute(new ThreadSafeClass(dbRepository));
}
}
因为
run()
终止,spring 假定应用程序已经完成并调用.close();
因此 closing 应用程序上下文并使其无法使用任何 spring 功能,例如存储库。计划的任务已经执行,但是上下文已经关闭,因此它们失败并抛出异常。
解决方法是等待任务完成后再退出运行方法。由于你的例子太少了,这只是一个例子。或者,您可以使用其他方法等待 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