带有 Spring Boot 的 Spring Data JPA 中的多个数据源,[重复]

Posted

技术标签:

【中文标题】带有 Spring Boot 的 Spring Data JPA 中的多个数据源,[重复]【英文标题】:Multiple DataSources In Spring Data JPA with Spring Boot, [duplicate] 【发布时间】:2017-10-28 20:05:18 【问题描述】:

当我尝试在 Spring Boot 中使用 Spring Data JPA 编写具有两个数据库的应用程序时。它不能创建数据库,它给定的例外。这是我的实现代码

应用类

package com.icarat.eshiksha;
@SpringBootApplication
public class Application  extends SpringBootServletInitializer 
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) 
        return application.sources(Application.class);
    
    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    

application.xml 文件

server.port=8080
server.contextPath=/Eshiksha

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db_shiksha2
spring.datasource.username=root
spring.datasource.password=*****
spring.datasource.validation-query=select 1

settings.datasource.driver-class-name=com.mysql.jdbc.Driver
settings.datasource.url=jdbc:mysql://127.0.0.1:3306/db_shiksha_settings2
settings.datasource.username=root
settings.datasource.password=*******
settings.datasource.validation-query=select 1

ShikshaDbConfig 类

package com.icarat.eshiksha.config;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "shikshaEntityManagerFactory", 
        transactionManagerRef = "shikshaTransactionManager",
        basePackages =  "com.icarat.eshiksha.repository" )
public class ShikshaDbConfig 


    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    @Autowired
    DataSource dataSource;

    @Bean(name = "shikshaManager")
    public EntityManager shikshaManager() 
        return shikshaEntityManagerFactory().createEntityManager();
    

    @Primary
    @Bean(name = "shikshaEntityManagerFactory")
    public EntityManagerFactory shikshaEntityManagerFactory() 

          Properties properties = new Properties();
            properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
            properties.setProperty("hibernate.hbm2ddl.auto","update");
            properties.setProperty("hibernate.show_sql", "false");

        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setJpaVendorAdapter(jpaVendorAdapter);
        emf.setJpaProperties(properties);
        emf.setPackagesToScan("com.icarat.eshiksha.database.entities");
        emf.setPersistenceUnitName("default");   // <- giving 'default' as name
        emf.afterPropertiesSet();
        return emf.getObject();
    

    @Bean(name = "shikshaTransactionManager")
    public PlatformTransactionManager shikshaTransactionManager() 
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(shikshaEntityManagerFactory());
        return tm;
       

ShikshaSettingsDbConfig 类

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "settingEntityManagerFactory", 
        transactionManagerRef = "shikshaSettingsTransactionManager",
        basePackages =  "com.icarat.eshiksha.settings.repository" )
public class ShikshaSettingsDbConfig 

     @Autowired
        JpaVendorAdapter jpaVendorAdapter;

        @Value("$settings.datasource.url")
        private String databaseUrl;

        @Value("$settings.datasource.username")
        private String username;

        @Value("$settings.datasource.password")
        private String password;

        @Value("$settings.datasource.driver-class-name")
        private String driverClassName;



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

        @Bean(name = "settingEntityManager")
        public EntityManager settingEntityManager() 
            return settingEntityManagerFactory().createEntityManager();
        

        @Bean(name = "settingEntityManagerFactory")
        public EntityManagerFactory settingEntityManagerFactory() 
             Properties properties = new Properties();
                properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                properties.setProperty("hibernate.hbm2ddl.auto","update");
                properties.setProperty("hibernate.show_sql", "false");
             properties.setProperty("hibernate.cache.use_second_level_cache", "true");
            properties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");

            LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
            emf.setDataSource(dataSource());
            emf.setJpaVendorAdapter(jpaVendorAdapter);
            emf.setPackagesToScan("com.icarat.eshiksha.settings.database.entites");   // <- package for entities
            emf.setPersistenceUnitName("settingPersistenceUnit");
            emf.setJpaProperties(properties);
            emf.afterPropertiesSet();
            return emf.getObject();
        

        @Bean(name = "settingsTransactionManager")
        public PlatformTransactionManager settingsTransactionManager() 
            return new JpaTransactionManager(settingEntityManagerFactory());
            

组织类

@Entity
@Table(name = "Organization")
public class Organization 

    @Id
@GeneratedValue(strategy=GenerationType.AUTO)   
    @Column(name="orgId")
    private String orgId;

    @Column(name="orgName", unique=true)
    private String orgName;

    @Column(name="orgAddress")
    private String orgAddress;

    @Column(name="pincode")
    private String pincode;


    @Column(name="boardOfEducation")
    private String boardOfEducation;

    @Column(name="recognizedBy")
    private String recognizedBy;

    @Column(name="affiliationNumber")
    private String affiliationNumber;


    @Column(name="faxNumber")
    private String faxNumber;


    @Column(name = "isActive")
    private boolean isActive = true;

    @OneToOne
    private OrganizationAdmin admin;

    @OneToMany(fetch = FetchType.LAZY, mappedBy="org", cascade=CascadeType.REMOVE)
    private List<Branch> branches =new ArrayList<Branch>();
//getter //setter 

OrganizationDAOImpl 类

package com.icarat.eshiksha.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import com.icarat.eshiksha.dao.OrganizationDAO;
import com.icarat.eshiksha.database.entities.Organization;
import com.icarat.eshiksha.dto.AddOrgRequestDTO;
import com.icarat.eshiksha.repository.OrganizationRepository;
import com.icarat.eshiksha.util.StringConstants;

@Service
public class OrganizationDAOImpl implements OrganizationDAO    

    @Autowired
    private OrganizationRepository organizationRepository;  

    @Override
    public String addOrganization(AddOrgRequestDTO request)    
        Organization org = createHomeEntity(request);
        try        
            organizationRepository.save(org);       
            return StringConstants.SUCCESS;
        catch(DataIntegrityViolationException e)      
            e.printStackTrace();                
            return null;
         catch(Exception e) 
            e.printStackTrace();        
            return null;
        
           

    private Organization createHomeEntity(final AddOrgRequestDTO request) 
        Organization home = new Organization();
        home.setOrgName(request.getOrgName());  
        home.setOrgAddress(request.getAddress());
        home.setPincode(request.getPincode());
        if(request.getFaxNumber()!=null)
        home.setFaxNumber(request.getFaxNumber());
        
        if(request.getBoardOfEducation()!=null)
            home.setBoardOfEducation(request.getBoardOfEducation());
            
            if(request.getRecognizedBy()!=null)
                home.setRecognizedBy(request.getRecognizedBy());
            
            if(request.getAffiliationNumber()!=null)
                home.setAffiliationNumber(request.getAffiliationNumber());
            
        return home;
    

OrganizationRepository 类

package com.icarat.eshiksha.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.icarat.eshiksha.database.entities.Organization;
@Repository
public interface OrganizationRepository extends JpaRepository<Organization, String>


抛出的异常是

 2017-05-28 16:08:16.061  WARN 4424 --- [           main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'organizationDAOImpl': Unsatisfied dependency expressed through field 'organizationRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'organizationRepository': Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'settingEntityManagerFactory' defined in class path resource [com/icarat/eshiksha/config/ShikshaSettingsDbConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'settingEntityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError
2017-05-28 16:08:16.070  INFO 4424 --- [           main] utoConfigurationReportLoggingInitializer : 

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-05-28 16:08:16.075 ERROR 4424 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'organizationDAOImpl': Unsatisfied dependency expressed through field 'organizationRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'organizationRepository': Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'settingEntityManagerFactory' defined in class path resource [com/icarat/eshiksha/config/ShikshaSettingsDbConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'settingEntityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.4.4.RELEASE.jar:1.4.4.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762) [spring-boot-1.4.4.RELEASE.jar:1.4.4.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:372) [spring-boot-1.4.4.RELEASE.jar:1.4.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-1.4.4.RELEASE.jar:1.4.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1187) [spring-boot-1.4.4.RELEASE.jar:1.4.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1176) [spring-boot-1.4.4.RELEASE.jar:1.4.4.RELEASE]
    at com.icarat.eshiksha.Application.main(Application.java:38) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'organizationRepository': Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'settingEntityManagerFactory' defined in class path resource [com/icarat/eshiksha/config/ShikshaSettingsDbConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'settingEntityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    ... 19 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'settingEntityManagerFactory' defined in class path resource [com/icarat/eshiksha/config/ShikshaSettingsDbConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'settingEntityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    ... 32 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'settingEntityManagerFactory' defined in class path resource [com/icarat/eshiksha/config/ShikshaSettingsDbConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'settingEntityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:519) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:508) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1189) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:261) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.getMetamodels(JpaMetamodelMappingContextFactoryBean.java:85) ~[spring-data-jpa-1.10.7.RELEASE.jar:na]
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:56) ~[spring-data-jpa-1.10.7.RELEASE.jar:na]
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:26) ~[spring-data-jpa-1.10.7.RELEASE.jar:na]
    at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:134) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    ... 39 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'settingEntityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    ... 57 common frames omitted
Caused by: java.lang.AbstractMethodError: null
    at org.hibernate.internal.CacheImpl.<init>(CacheImpl.java:49) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:28) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:20) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.service.internal.SessionFactoryServiceRegistryImpl.initiateService(SessionFactoryServiceRegistryImpl.java:49) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:254) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:228) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.service.internal.SessionFactoryServiceRegistryImpl.getService(SessionFactoryServiceRegistryImpl.java:68) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:244) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at com.icarat.eshiksha.config.ShikshaSettingsDbConfig.settingEntityManagerFactory(ShikshaSettingsDbConfig.java:71) ~[classes/:na]
    at com.icarat.eshiksha.config.ShikshaSettingsDbConfig$$EnhancerBySpringCGLIB$$1d6ef92.CGLIB$settingEntityManagerFactory$0(<generated>) ~[classes/:na]
    at com.icarat.eshiksha.config.ShikshaSettingsDbConfig$$EnhancerBySpringCGLIB$$1d6ef92$$FastClassBySpringCGLIB$$b22a78eb.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at com.icarat.eshiksha.config.ShikshaSettingsDbConfig$$EnhancerBySpringCGLIB$$1d6ef92.settingEntityManagerFactory(<generated>) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_73]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_73]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_73]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_73]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    ... 58 common frames omitted

我该如何解决这个问题。请帮忙找出来。谢谢

【问题讨论】:

【参考方案1】:

我创建了一个有效的POC here。 README.md 中提供了说明。此解决方案使用 Gradle 构建并使用 Docker 来保留两个 MySQL 实例和一个暴露 REST 端点的 SpringBoot 应用程序。

关于您的实施的几点:

1.使用唯一的 bean 名称

您定义了与您的两个数据源相对应的两个配置。您需要使用@Bean("name") 命名每个bean,并使用@Qualifier("name") 按名称注入它们。

还有一个配置需要用@Primary注释它的bean,否则将不起作用,不要问我为什么。如果您有多个相同类型的 bean 按类型注入而没有任何进一步的限定,则接收错误是正常的,但即使注入使用 @Qualifier("name") 限定,似乎也会出现错误,其中 "name" 是唯一的。

例如,其中一种配置可能如下所示:

POC MySqlSource1Config.java.

package my.java.spring.jpa.multi.repositories.config;

import my.java.spring.jpa.multi.models.Organization;
import my.java.spring.jpa.multi.repositories.source1.Source1OrganizationRepositoryImpl;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

/**
 * Repository configuration.
 * @EnableJpaRepositories to enable JPA automatic repositories.
 */
@Configuration
@EnableJpaRepositories(
        basePackageClasses =  Source1OrganizationRepositoryImpl.class ,
        entityManagerFactoryRef = MySqlSource1Config.EntityManagerFactoryBeanName,
        transactionManagerRef = MySqlSource1Config.TransactionManagerBeanName
)
public class MySqlSource1Config 

    public static final String PrefixName = "source1";
    public static final String DataSourceBeanName = PrefixName + ".data-source";
    public static final String JpaVendorAdapterBeanName = PrefixName + "jpa-vendor-adapter";
    public static final String EntityManagerFactoryBeanName = PrefixName + ".entity-manager-factory";
    public static final String TransactionManagerBeanName = PrefixName + ".transaction-manager";
    public static final String RepositoryBeanName = PrefixName + ".repository";

    @Bean(TransactionManagerBeanName)
    @Primary
    public PlatformTransactionManager transactionManager(
            @Qualifier(EntityManagerFactoryBeanName) EntityManagerFactory entityManagerFactory) 
        return new JpaTransactionManager(entityManagerFactory);
    

    @Bean(EntityManagerFactoryBeanName)
    @Primary
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            @Qualifier(DataSourceBeanName) DataSource dataSource,
            @Qualifier(JpaVendorAdapterBeanName) JpaVendorAdapter vendorAdapter) 

        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
        entityManagerFactoryBean.setJpaDialect(new HibernateJpaDialect());
        entityManagerFactoryBean.setPackagesToScan(Organization.class.getPackage().getName());
        entityManagerFactoryBean.setPersistenceUnitName("mysqlsource1");
        entityManagerFactoryBean.afterPropertiesSet();

        return entityManagerFactoryBean;
    

    @Bean(JpaVendorAdapterBeanName)
    @Primary
    @ConfigurationProperties(prefix = "source1.mysql.jpa")
    public JpaVendorAdapter jpaVendorAdapter() 
        return new HibernateJpaVendorAdapter();
    

    @Bean(DataSourceBeanName)
    @Primary
    @ConfigurationProperties(prefix = "source1.mysql.datasource")
    public DataSource dataSource() 
        return DataSourceBuilder.create().build();
    

2。按 bean 名称注入 bean

因为为同一类型找到了多个 bean 定义,所以您应该使用 @Qualifier() 的名称注入 bean:

@Bean(TransactionManagerBeanName)
@Primary
public PlatformTransactionManager transactionManager(
        @Qualifier(EntityManagerFactoryBeanName) EntityManagerFactory entityManagerFactory) 
    return new JpaTransactionManager(entityManagerFactory);

相比之下,以下是从您的代码中提取的:

@Bean(name = "shikshaTransactionManager")
public PlatformTransactionManager shikshaTransactionManager() 
    JpaTransactionManager tm = new JpaTransactionManager();
    tm.setEntityManagerFactory(shikshaEntityManagerFactory());
    return tm;
   

这不行,因为shikshaEntityManagerFactory() 将创建EntityManagerFactory 的新实例,而不是注入现有的bean。

3.当你有EntityManagerFactory时,不需要显式定义EntityManager

以下内容摘自您的问题:

@Bean(name = "shikshaManager")
public EntityManager shikshaManager() 
    return shikshaEntityManagerFactory().createEntityManager();


@Primary
@Bean(name = "shikshaEntityManagerFactory")
public EntityManagerFactory shikshaEntityManagerFactory()  ... 

一点是两者都已定义,另一点是,如果您仍然需要EntityManager,那么您应该注入EntityManagerFactory bean,而不是执行方法调用shikshaEntityManagerFactory(),它会生成EntityManagerFactory 的另一个实例.

4.简化配置

您可以使用 @ConfigurationProperties 而不是 @Value 将多个配置属性加载到您的 bean 中,例如:

    @Bean(JpaVendorAdapterBeanName)
    @Primary
    @ConfigurationProperties(prefix = "source1.mysql.jpa")
    public JpaVendorAdapter jpaVendorAdapter() 
        return new HibernateJpaVendorAdapter();
    

    @Bean(DataSourceBeanName)
    @Primary
    @ConfigurationProperties(prefix = "source1.mysql.datasource")
    public DataSource dataSource() 
        return DataSourceBuilder.create().build();
    

然后两个数据源的application.yml 将如下所示:

source1:
  mysql:
    jpa:
      show-sql: true
      generate-ddl: true
      database: MYSQL
    datasource:
      platform: postgres
      url: jdbc:mysql://localhost:3307/test1
      username: myuser1
      password: mypass1
      driverClassName: com.mysql.cj.jdbc.Driver
source2:
  mysql:
    jpa:
      show-sql: true
      generate-ddl: true
      database: MYSQL
    datasource:
      platform: postgres
      url: jdbc:mysql://localhost:3308/test2
      username: myuser2
      password: mypass2
      driverClassName: com.mysql.cj.jdbc.Driver

请注意,jpa 被加载到 JpaVendorAdapter 中,datasource 被加载到 DataSource 中。

5.将数据源存储库分开

如果您需要对多个数据源使用相同的实体和存储库,那么您可以保留一个公共接口OrganizationRepository,并拥有单独的接口Source1OrganizationRepository 和IMPL Source1OrganizationRepositoryImpl

另一方面,如果您有多个数据源不使用的实体和存储库(例如:由 source1 管理的组织和由 source2 管理的用户),那么将有不同的包由不同的源管理但不需要通用接口。

这允许将存储库 bean 命名为:

@Repository(MySqlSource1Config.RepositoryBeanName)
public interface Source1OrganizationRepository extends OrganizationRepository 

为了区别于其他数据源存储库。

这些已配置,就像您已经在配置中使用它们一样(注意basePackageClasses):

@Configuration
@EnableJpaRepositories(
        basePackageClasses =  Source1OrganizationRepositoryImpl.class ,
        entityManagerFactoryRef = MySqlSource1Config.EntityManagerFactoryBeanName,
        transactionManagerRef = MySqlSource1Config.TransactionManagerBeanName
)
public class MySqlSource1Config  ... 

然后可以将这些存储库进一步注入到控制器、服务或任何其他组件中,例如:

@RestController
@RequestMapping("/v1/organization")
public class OrganizationController 

    private final OrganizationRepository organizationRepositoryFromSource1;
    private final OrganizationRepository organizationRepositoryFromSource2;

    @Autowired
    public OrganizationController(
            @Qualifier(MySqlSource1Config.RepositoryBeanName) OrganizationRepository organizationRepositoryFromSource1,
            @Qualifier(MySqlSource2Config.RepositoryBeanName) OrganizationRepository organizationRepositoryFromSource2) 

        this.organizationRepositoryFromSource1 = organizationRepositoryFromSource1;
        this.organizationRepositoryFromSource2 = organizationRepositoryFromSource2;
    

...

同一实体可用于多个数据源,由EntityManager 加载,并可在EntityManagerFactory 内部配置:

@Bean(EntityManagerFactoryBeanName)
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
        @Qualifier(DataSourceBeanName) DataSource dataSource,
        @Qualifier(JpaVendorAdapterBeanName) JpaVendorAdapter vendorAdapter) 

...
entityManagerFactoryBean.setPackagesToScan(Organization.class.getPackage().getName());
...


注意:application.ymlapplication-docker.yml 中我使用了source1.mysql.jpa.generate-ddl: true。这意味着与EntityManager 找到的实体对应的表和模式将在 MySQL 数据库中自动创建。如果您通过其他方式管理数据库架构,例如创建脚本并使用FlyWayLiquidbase 迁移它们,那么您可能需要将该选项设置为false 以采用您自己的流程。

【讨论】:

您的解决方案不起作用,因为 RepositoryBeanName 与数据源配置无关

以上是关于带有 Spring Boot 的 Spring Data JPA 中的多个数据源,[重复]的主要内容,如果未能解决你的问题,请参考以下文章

带有 Spring Boot 应用程序的 docker secret 在 docker swarm 模式 /run/secrets 下不起作用

带有 FeignClient 的 Spring Boot RepositoryRestResource

带有 spring-boot 和 spring-security 的 JWT

带有 spring-boot-starter-web 的 Spring Cloud Gateway

带有 Spring Boot 的 Spring Restful 服务 - NoSuchBeanDefinitionException

带有 MVC 的 Spring Boot SOAP Web 服务