【发布时间】:2016-01-15 16:53:48
【问题描述】:
我有一个包含 3 个不同数据源的项目。如果项目是从 spring-boot 运行的,它工作正常:只运行这些依赖项:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>RELEASE</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-web</artifactId>-->
<!--</dependency>-->
这是一个数据源,它们几乎都一样,只是更改了 bean 名称和数据库信息
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "emfIntranet", transactionManagerRef = "tmIntranet", basePackages = {"com.vnt.intranet.repositories"})
@ConfigurationProperties(prefix = "databases.sistemas")
public class IntranetPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
@Primary
@Bean(name = "dsIntranet")
public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
private EclipseLinkJpaVendorAdapter getEclipseLinkJpaVendorAdapter() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.PostgreSQLPlatform");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
@Primary
@Bean(name = "emfIntranet")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getEclipseLinkJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("com.vnt.intranet.entities");
factoryBean.setPersistenceUnitName("intranet");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE / FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Primary
@Bean(name = "tmIntranet")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
我可以毫无问题地访问所有数据源...其中一个带有@Primary 注释。
但是如果我取消注释 spring-boot-starter-web 依赖,它会破坏它并给我:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: more than one 'primary' bean found among candidates: [emfIntranet, entityManagerFactory, emfMkRadius, emfMkData]
我正在尝试将其转换为网络项目,但没有成功...
有什么想法吗?
编辑 为清楚起见添加其他类:
MkDataPersistence.class
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "emfMkData", transactionManagerRef = "tmMkData", basePackages = {"org.example.mkdata.repositories"})
@ConfigurationProperties(prefix = "databases.mkdata")
public class MkDataPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
@Bean(name = "dsMkData")
javax.sql.DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
@Bean
HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
@Bean(name = "emfMkData")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("org.example.mkdata.entities");
factoryBean.setPersistenceUnitName("mkdata");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE / FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean(name = "tmMkData")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
MkRadiusPersistence.class
@Configuration
@EnableTransactionManagement()
@EnableJpaRepositories(entityManagerFactoryRef = "emfMkRadius", transactionManagerRef = "tmMkRadius", basePackages = {"org.example.mkradius.repositories"})
@ConfigurationProperties(prefix = "databases.mkradius")
public class MkRadiusPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
@Bean(name = "dsMkRadius")
javax.sql.DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
@Bean
HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
@Bean(name = "emfMkRadius")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("org.example.mkradius.entities");
factoryBean.setPersistenceUnitName("mkradius");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE / FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean(name = "tmMkRadius")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
编辑 2
应用程序类
@Configuration
@ComponentScan(basePackages = { "org.example.startup" })
@EnableAutoConfiguration
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
CableRouteRepository cableRouteRepository;
@Autowired
CityRepository cityRepository;
@Autowired
RadAcctRepository radAcctRepository;
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.showBanner(false)
.sources(Application.class)
.run(args);
Application app = context.getBean(Application.class);
// for (String bean: context.getBeanDefinitionNames()) {
// logger.info(bean);
// }
app.start();
}
private void start() {
logger.info("Application.start()");
logger.info("{}", cableRouteRepository.findAll());
logger.info("{}", cityRepository.findAll());
logger.info("{}", radAcctRepository.findTest());
}
}
这是入门类...我打印了每个存储库作为测试(这里的每个存储库都在不同的数据源上)...只要我在类路径上没有 spring-starter-web,它们就可以正常工作.
编辑 3
Github 回购 https://github.com/mtrojahn/test-multiple-databases
我希望我做对了...我从来没有真正使用过 Github :)
编辑 4
Github 使用失败的代码正确更新。
提醒一下,如果下面的依赖项被注释,代码可以工作:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如果上面的依赖没有注释,但是下面的代码在 IntranetPersistence.class 中发生了变化:
@Primary
@Bean(name = "emfIntranet")
到
@Primary
@Bean(name = "entityManagerFactory")
它会覆盖默认 bean 并开始失败:
Caused by: java.lang.IllegalArgumentException: Not an managed type: class org.example.intranet.entities.CableRoute
【问题讨论】:
-
emfMkRadius和emfMkData声明在哪里?我可以看到emfIntranet是@Primary,也是另外两个之一吗? -
我会和他们一起编辑,但他们几乎是一样的,所以我没有把他们都发出去。
-
Spring Boot 的
entityManagerFactorybean 是@Primary但它应该被你的任何一个EntityManagerFactorybean 关闭,因为它的创建取决于它们在上下文中不是EntityManagerFactorybean .你的主要课程是什么样的?您是否直接引用任何 Boot 的自动配置类? -
主课对我来说看起来不错。你能在某个地方分享一个 repo,其中包含重现问题所需的所有代码吗?
-
感谢您的关注! :) 我在测试用例中添加了一个 repo。
标签: spring-mvc spring-boot spring-data-jpa spring-data-rest