Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring Boot,具有多个数据源的Spring数据JPA_Java_Spring_Jpa_Spring Data_Spring Boot - Fatal编程技术网

Java Spring Boot,具有多个数据源的Spring数据JPA

Java Spring Boot,具有多个数据源的Spring数据JPA,java,spring,jpa,spring-data,spring-boot,Java,Spring,Jpa,Spring Data,Spring Boot,我正试图用SpringBoot和SpringDataJPA将每个@Repositories连接到不同的数据源。我引用了以下内容作为参考。下面是我试图使用SpringDataJPA实现类似解决方案时使用的代码 CustomerDbConfig.java(第一个数据源连接) CustomerDbConfig.java(第二个数据源) Customer.java(模型) Order.java(型号) CustomerRepository.java public interface CustomerR

我正试图用SpringBoot和SpringDataJPA将每个@Repositories连接到不同的数据源。我引用了以下内容作为参考。下面是我试图使用SpringDataJPA实现类似解决方案时使用的代码

CustomerDbConfig.java(第一个数据源连接)

CustomerDbConfig.java(第二个数据源)

Customer.java(模型)

Order.java(型号)

CustomerRepository.java

public interface CustomerRepository extends JpaRepository<Customer, Integer>{

}
public interface OrderRepository extends JpaRepository<Order, Integer> {

}
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringApplication{

       public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }

        @Bean
        public ServletRegistrationBean h2Console() {
            ServletRegistrationBean reg = new ServletRegistrationBean(new WebServlet(), "/console/*");
            reg.setLoadOnStartup(1);
            return reg;
        }
}
在启动过程中,会引发以下异常:

-10-10 15:45:24.757 ERROR 1549 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerTransactionManager' defined in class path resource [com/mm/boot/multidb/CustomerConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
    at com.mm.boot.multidb.Application.main(Application.java:17)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:974)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
    ... 18 common frames omitted

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerTransactionManager' defined in class path resource [com/mm/boot/multidb/CustomerConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
    at com.mm.boot.multidb.Application.main(Application.java:17)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:974)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
    ... 18 more
示例的完整代码可以在GitHub()上找到


提前感谢您的帮助。

我查看了您在GitHub上提供的源代码。配置中有几个错误/打字错误

在CustomerDbConfig/OrderDbConfig中,您应参考customerEntityManager,包应指向现有包:

@Configuration
@EnableJpaRepositories(
    entityManagerFactoryRef = "customerEntityManager",
    transactionManagerRef = "customerTransactionManager",
    basePackages = {"com.mm.boot.multidb.repository.customer"})
public class CustomerDbConfig {
customerEntityManager和orderEntityManager中要扫描的包都没有指向正确的包:

em.setPackagesToScan("com.mm.boot.multidb.model.customer");
此外,注射适当的EntityManagerFactory也不起作用。应该是:

@Bean(name = "customerTransactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory customerEntityManager){

}
以上是导致问题和异常的原因。在@Bean方法中提供名称时,您可以确保注入了正确的EMF

我所做的最后一件事是禁用JpaRepositories的自动配置:

@EnableAutoConfiguration(exclude = JpaRepositoriesAutoConfiguration.class)

在所有修复之后,应用程序将按照您的预期启动

通过使用@EnableAutoConfiguration和application.properties,还有另一种拥有多个数据源的方法

基本上,将多个数据源配置信息放在application.properties上,并通过@EnableAutoConfiguration自动为第一个数据源生成默认设置(dataSource和entityManagerFactory)。但是对于下一个数据源,可以通过属性文件中的信息手动创建dataSource、entityManagerFactory和transactionManager

下面是我设置两个数据源的示例。 第一个数据源由@EnableAutoConfiguration设置,它只能为一个配置而不是多个配置分配。这将通过DataSourceTransactionManager生成“transactionManager”,它看起来是由注释生成的默认transactionManager。但是,我已经看到,只有在默认DataSourceTransactionManager以及存在多个事务管理器的情况下,调度线程池中的线程上出现了事务未开始问题。 因此,我通过JpaTransactionManager手动创建transactionManager,并为第一个数据源分配“transactionManager”bean名称和默认entityManagerFactory。第一个数据源的JpaTransactionManager肯定解决了ScheduledThreadPool线程上的奇怪事务问题

Spring Boot 1.3.0.版本的更新

我发现我以前使用@EnableAutoConfiguration进行的默认数据源配置在使用SpringBoot1.3版本查找entityManagerFactory时出现问题。在我介绍自己的transactionManager之后,@EnableAutoConfiguration可能不会生成默认entityManagerFactory。 所以现在我自己创建entityManagerFactory。所以我不需要使用@EntityScan。因此,通过@EnableAutoConfiguration,我似乎越来越了解设置

第二个数据源是在没有@EnableAutoConfiguration的情况下设置的,并通过手动方式创建“另一个TransactionManager”

因为有多个transactionManager扩展自PlatformTransactionManager,所以我们应该指定在每个@Transactional注释上使用哪个transactionManager

默认存储库配置

@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager",
        basePackages = {"com.mysource.repository"})
public class RepositoryConfig {
    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    @Autowired
    DataSource dataSource;

    @Bean(name = "entityManager")
    public EntityManager entityManager() {
        return entityManagerFactory().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactory")
    public EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setJpaVendorAdapter(jpaVendorAdapter);
        emf.setPackagesToScan("com.mysource.model");
        emf.setPersistenceUnitName("default");   // <- giving 'default' as name
        emf.afterPropertiesSet();
        return emf.getObject();
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(entityManagerFactory());
        return tm;
    }
}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "anotherEntityManagerFactory",
        transactionManagerRef = "anotherTransactionManager",
        basePackages = {"com.mysource.anothersource.repository"})
public class AnotherRepositoryConfig {
    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    @Value("${another.datasource.url}")
    private String databaseUrl;

    @Value("${another.datasource.username}")
    private String username;

    @Value("${another.datasource.password}")
    private String password;

    @Value("${another.dataource.driverClassName}")
    private String driverClassName;

    @Value("${another.datasource.hibernate.dialect}")
    private String dialect;

    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseUrl, username, password);
        dataSource.setDriverClassName(driverClassName);
        return dataSource;
    }

    @Bean(name = "anotherEntityManager")
    public EntityManager entityManager() {
        return entityManagerFactory().createEntityManager();
    }

    @Bean(name = "anotherEntityManagerFactory")
    public EntityManagerFactory entityManagerFactory() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", dialect);

        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource());
        emf.setJpaVendorAdapter(jpaVendorAdapter);
        emf.setPackagesToScan("com.mysource.anothersource.model");   // <- package for entities
        emf.setPersistenceUnitName("anotherPersistenceUnit");
        emf.setJpaProperties(properties);
        emf.afterPropertiesSet();
        return emf.getObject();
    }

    @Bean(name = "anotherTransactionManager")
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory());
    }
}
为@Transactional注释选择适当的transactionManager

第一个数据源的服务

@Service("mainService")
@Transactional("transactionManager")
public class DefaultDataSourceServiceImpl implements DefaultDataSourceService       
{

   //

}
@Service("anotherService")
@Transactional("anotherTransactionManager")
public class AnotherDataSourceServiceImpl implements AnotherDataSourceService 
{

   //

}
另一数据源的服务

@Service("mainService")
@Transactional("transactionManager")
public class DefaultDataSourceServiceImpl implements DefaultDataSourceService       
{

   //

}
@Service("anotherService")
@Transactional("anotherTransactionManager")
public class AnotherDataSourceServiceImpl implements AnotherDataSourceService 
{

   //

}

这是我的解决办法。基于spring-boot.1.2.5.1版本

应用程序属性

DataSourceConfig.java


不知道为什么,但它是有效的。两种配置相同,只需将xxx更改为您的名称即可

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "xxxEntityManager",
    transactionManagerRef = "xxxTransactionManager",
    basePackages = {"aaa.xxx"})
 public class RepositoryConfig {
@Autowired
private Environment env;

@Bean
@Primary
@ConfigurationProperties(prefix="datasource.xxx")
public DataSource xxxDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
public LocalContainerEntityManagerFactoryBean xxxEntityManager() {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(xxxDataSource());
    em.setPackagesToScan(new String[] {"aaa.xxx"});

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    HashMap<String, Object> properties = new HashMap<String, Object>();
    properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
    properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
    properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
    em.setJpaPropertyMap(properties);

    return em;
}

@Bean(name = "xxxTransactionManager")
public PlatformTransactionManager xxxTransactionManager() {
    JpaTransactionManager tm = new JpaTransactionManager();
    tm.setEntityManagerFactory(xxxEntityManager().getObject());
    return tm;
}
@配置
@启用事务管理
@授权代理(
entityManagerFactoryRef=“xxxEntityManager”,
transactionManagerRef=“xxxTransactionManager”,
basePackages={“aaa.xxx”})
公共类RepositoryConfig{
@自动连线
私人环境署;
@豆子
@初级的
@配置属性(前缀=“datasource.xxx”)
公共数据源xxxDataSource(){
返回DataSourceBuilder.create().build();
}
@豆子
public LocalContainerEntityManagerFactoryBean xxxEntityManager(){
LocalContainerEntityManagerFactoryBean em=新的LocalContainerEntityManagerFactoryBean();
em.setDataSource(xxxDataSource());
em.setPackagesToScan(新字符串[]{“aaa.xxx”});
HibernateJavaEndorapter vendorAdapter=新的HibernateJavaEndorapter();
em.setjpavendor适配器(供应商适配器);
HashMap属性=新建HashMap();
properties.put(“hibernate.show_sql”,env.getProperty(“hibernate.show_sql”);
properties.put(“hibernate.hbm2ddl.auto”,env.getProperty(“hibernate.hbm2ddl.auto”);
properties.put(“hibernate.dial”,env.getProperty(“hibernate.dial”);
em.setJpaPropertyMap(属性);
返回em;
}
@Bean(name=“xxxTransactionManager”)
公共平台TransactionManager xxxTransactionManager(){
JpaTransactionManager tm=新的JpaTransactionManager();
tm.setEntityManager工厂(xxxeEntityManager().getObject());
返回tm;
}

}

多亏了Steve Park和Rafal Borowiec的回答,我的代码得以运行,但是,我有一个问题:DriverManager数据源是一个“简单”的实现,它不会给你一个连接池(检查)

因此,我替换了为
secondDB
返回
DataSource
的函数

public DataSource <secondaryDB>DataSource() {
    // use DataSourceBuilder and NOT DriverManagerDataSource 
    // as this would NOT give you ConnectionPool
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.url(databaseUrl);
    dataSourceBuilder.username(username);
    dataSourceBuilder.password(password);
    dataSourceBuilder.driverClassName(driverClassName);
    return dataSourceBuilder.build();
}
公共数据源数据源(){ //使用DataSourceBuilder而不是DriverManager DataSource //a
@Service("anotherService")
@Transactional("anotherTransactionManager")
public class AnotherDataSourceServiceImpl implements AnotherDataSourceService 
{

   //

}
first.datasource.driver-class-name=com.mysql.jdbc.Driver
first.datasource.url=jdbc:mysql://127.0.0.1:3306/test
first.datasource.username=
first.datasource.password=
first.datasource.validation-query=select 1

second.datasource.driver-class-name=com.mysql.jdbc.Driver
second.datasource.url=jdbc:mysql://127.0.0.1:3306/test2
second.datasource.username=
second.datasource.password=
second.datasource.validation-query=select 1
@Configuration
public class DataSourceConfig {
    @Bean
    @Primary
    @ConfigurationProperties(prefix="first.datasource")
    public DataSource firstDataSource() {
        DataSource ds =  DataSourceBuilder.create().build();
        return ds;
    }

    @Bean
    @ConfigurationProperties(prefix="second.datasource")
    public DataSource secondDataSource() {
        DataSource ds =  DataSourceBuilder.create().build();
        return ds;
    }
}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "xxxEntityManager",
    transactionManagerRef = "xxxTransactionManager",
    basePackages = {"aaa.xxx"})
 public class RepositoryConfig {
@Autowired
private Environment env;

@Bean
@Primary
@ConfigurationProperties(prefix="datasource.xxx")
public DataSource xxxDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
public LocalContainerEntityManagerFactoryBean xxxEntityManager() {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(xxxDataSource());
    em.setPackagesToScan(new String[] {"aaa.xxx"});

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    HashMap<String, Object> properties = new HashMap<String, Object>();
    properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
    properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
    properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
    em.setJpaPropertyMap(properties);

    return em;
}

@Bean(name = "xxxTransactionManager")
public PlatformTransactionManager xxxTransactionManager() {
    JpaTransactionManager tm = new JpaTransactionManager();
    tm.setEntityManagerFactory(xxxEntityManager().getObject());
    return tm;
}
public DataSource <secondaryDB>DataSource() {
    // use DataSourceBuilder and NOT DriverManagerDataSource 
    // as this would NOT give you ConnectionPool
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.url(databaseUrl);
    dataSourceBuilder.username(username);
    dataSourceBuilder.password(password);
    dataSourceBuilder.driverClassName(driverClassName);
    return dataSourceBuilder.build();
}