在一项服务中使用 jdbcTemplates 访问多个数据源 class
Access multiple datasources with jdbcTemplates in one Service class
这是我的案例:
我有两个数据库:一个sybase 和一个mssql。我希望在一个服务中访问两个数据库 class。例如,我想从sybase获取一些数据,然后我需要在mssql上做一些更新。
我已经根据网上找到的多个示例设置了两个数据源,但我无法访问我的第二个数据库 (sybase)。
这是我的代码:
pom.xml
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
# Database
# spring.datasource.jndi-name=jdbc/database1
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.datasource.url=jdbc:jtds:sqlserver://database1/db_aes
spring.datasource.username=user1
spring.datasource.password=password1
# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
# 2nd Database
spring.secondDatasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.secondDatasource.url=jdbc:jtds:sybase://database2/aidcconfig
spring.secondDatasource.username=user2
spring.secondDatasource.password=password2
spring.secondDatasource.hibernate.dialect = org.hibernate.dialect.SybaseASE15Dialect
spring.secondDatasource.testWhileIdle = true
spring.secondDatasource.validationQuery = SELECT 1
# Show or not log for each sql query
spring.jpa.show-sql = false
# Hibernate ddl auto (create, create-drop, update, validate)
spring.jpa.hibernate.ddl-auto = validate
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.EJB3NamingStrategy
# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager)
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.SQLServerDialect
com.ibm.websphere.persistence.ApplicationsExcludedFromJpaProcessing=*
fileUploadServiceImpl
@Component("fileUploadService")
@Transactional
public class FileUploadServiceImpl implements FileUploadService {
@Autowired
@Qualifier("dbAesJdbcTemplate")
JdbcTemplate dbAesJdbcTemplate;
@Autowired
@Qualifier("aidcconfigJdbcTemplate")
JdbcTemplate aidcconfigJdbcTemplate;
private int uploadId = 1;
private void testDB(){
String db = aidcconfigJdbcTemplate.queryForObject("select db_name()", String.class);
System.out.println("database name: " + db);
}
...
}
DbAesDataSource
package config.database;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "dbAesEntityManagerFactory",
transactionManagerRef = "dbAesTransactionManager",
basePackages = {"web.fileUpload.repo.db_aes.dao"}
)
public class DbAesDataSource {
@Primary
@Bean(name="dbAesDataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dbAesDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name="dbAesJdbcTemplate")
public JdbcTemplate dbAesJdbcTemplate(@Qualifier("dbAesDataSource") DataSource dbAesDataSource)
{
return new JdbcTemplate(dbAesDataSource);
}
@Bean(name="dbAesEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean dbAesEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("dbAesDataSource") DataSource dbAesDataSource) {
return builder
.dataSource(dbAesDataSource)
.packages("web.fileUpload.repo.db_aes.models")
.build();
}
@Bean(name = "dbAesTransactionManager")
public PlatformTransactionManager dbAesTransactionManager(
@Qualifier("dbAesEntityManagerFactory") EntityManagerFactory dbAesEntityManagerFactory) {
return new JpaTransactionManager(dbAesEntityManagerFactory);
}
}
AidcconfigDataSource
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "aidcconfigEntityManagerFactory",
transactionManagerRef = "aidcconfigTransactionManager",
basePackages = {"web.fileUpload.repo.aidcconfig.dao"}
)
public class AidcconfigDataSource {
@Bean(name="aidcconfigDataSource")
@ConfigurationProperties(prefix = "spring.secondDatasource")
public DataSource aidcconfigDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name="aidcconfigJdbcTemplate")
public JdbcTemplate aidcconfigJdbcTemplate(@Qualifier("aidcconfigDataSource") DataSource aidcconfigDataSource)
{
return new JdbcTemplate(aidcconfigDataSource);
}
@Bean(name="aidcconfigEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean aidcconfigEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("aidcconfigDataSource") DataSource aidcconfigDataSource) {
return builder
.dataSource(aidcconfigDataSource)
.packages("web.fileUpload.repo.aidcconfig.models")
.build();
}
@Bean(name = "aidcconfigTransactionManager")
public PlatformTransactionManager aidcconfigTransactionManager(
@Qualifier("aidcconfigEntityManagerFactory") EntityManagerFactory aidcconfigEntityManagerFactory) {
return new JpaTransactionManager(aidcconfigEntityManagerFactory);
}
}
这是我的错误:
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.3.5.RELEASE:run (default-cli) on
project testUpload: An exception occurred while running. null: InvocationTargetException: Error creating bean with
name 'fileDownloadController': Injection of autowired dependencies failed; nested exception is org.springframework
.beans.factory.BeanCreationException: Could not autowire field: private web.fileUpload.services.FileUploadService w
eb.fileUpload.controller.FileDownloadController.fileUploadService; nested exception is org.springframework.beans.fa
ctory.BeanCreationException: Error creating bean with name 'fileUploadService': Injection of autowired dependencies
failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org
.springframework.jdbc.core.JdbcTemplate web.fileUpload.services.FileUploadServiceImpl.dbAesJdbcTemplate; nested exc
eption is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springfr
amework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidat
e for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=tr
ue), @org.springframework.beans.factory.annotation.Qualifier(value=dbAesJdbcTemplate)} -> [Help 1]
如果我删除了 FileUploadServiceImpl 中的限定符,那么任何 jdbcTemplate 都将只连接到我的 db_aes 主数据库。如何使用 jdbcTemplate 访问我的第二个数据源?
以下是我使用的一些参考资料:
Spring Boot, Spring Data JPA with multiple DataSources
https://www.infoq.com/articles/Multiple-Databases-with-Spring-Boot
Multiple DataSource and JdbcTemplate in Spring Boot (> 1.1.0)
试验#1
我注意到它无法创建 bean,因此我在 AidcconfigDataSource class 中放置了一些记录器。结果,我没有看到我的方法正在执行。因此,我假设应用程序没有读取我的 AidcconfigDataSource class.
我将配置文件夹从 java/config 移至 java/web/config:
现在我有另一个错误:
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.3.5.RELEASE:run (default-cli) on
project testUpload: An exception occurred while running. null: InvocationTargetException: Error creating bean with
name 'dataSourceInitializerPostProcessor': Injection of autowired dependencies failed; nested exception is org.spr
ingframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.beans.facto
ry.BeanFactory org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerPostProcessor.beanFactory; nested e
xception is org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'aidc
configDataSource' defined in class path resource [web/config/database/AidcconfigDataSource.class]: factory-bean ref
erence points back to the same bean definition -> [Help 1]
试用#2
我已经将我的 bean 名称从 aidcconfigDataSource 更改为 aidcconfigDS 并且与主数据源相同。另外,我在 application.properties 中添加了 "spring.jpa.open_in_view = false"。然而,另一个错误发生了。如何以正确的方式做到这一点?
2016-11-03 09:28:16.118 ERROR 11412 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.servic
e() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exce
ption is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springf
ramework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: dbAesTransa
ctionManager,aidcconfigTransactionManager] with root cause
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.
transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: dbAesTransactionMana
ger,aidcconfigTransactionManager
我认为 Spring Boot 正在尝试实例化 2 个具有相同名称的 bean:
aidcconfigDataSource
。
一个是你的配置 class AidcconfigDataSource.class
另一个是 bean:
@Bean(name="aidcconfigDataSource")
@ConfigurationProperties(prefix = "spring.secondDatasource")
public DataSource aidcconfigDataSource(){
return DataSourceBuilder.create().build();
}
这是我的案例: 我有两个数据库:一个sybase 和一个mssql。我希望在一个服务中访问两个数据库 class。例如,我想从sybase获取一些数据,然后我需要在mssql上做一些更新。
我已经根据网上找到的多个示例设置了两个数据源,但我无法访问我的第二个数据库 (sybase)。
这是我的代码:
pom.xml
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
# Database
# spring.datasource.jndi-name=jdbc/database1
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.datasource.url=jdbc:jtds:sqlserver://database1/db_aes
spring.datasource.username=user1
spring.datasource.password=password1
# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
# 2nd Database
spring.secondDatasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.secondDatasource.url=jdbc:jtds:sybase://database2/aidcconfig
spring.secondDatasource.username=user2
spring.secondDatasource.password=password2
spring.secondDatasource.hibernate.dialect = org.hibernate.dialect.SybaseASE15Dialect
spring.secondDatasource.testWhileIdle = true
spring.secondDatasource.validationQuery = SELECT 1
# Show or not log for each sql query
spring.jpa.show-sql = false
# Hibernate ddl auto (create, create-drop, update, validate)
spring.jpa.hibernate.ddl-auto = validate
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.EJB3NamingStrategy
# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager)
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.SQLServerDialect
com.ibm.websphere.persistence.ApplicationsExcludedFromJpaProcessing=*
fileUploadServiceImpl
@Component("fileUploadService")
@Transactional
public class FileUploadServiceImpl implements FileUploadService {
@Autowired
@Qualifier("dbAesJdbcTemplate")
JdbcTemplate dbAesJdbcTemplate;
@Autowired
@Qualifier("aidcconfigJdbcTemplate")
JdbcTemplate aidcconfigJdbcTemplate;
private int uploadId = 1;
private void testDB(){
String db = aidcconfigJdbcTemplate.queryForObject("select db_name()", String.class);
System.out.println("database name: " + db);
}
...
}
DbAesDataSource
package config.database;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "dbAesEntityManagerFactory",
transactionManagerRef = "dbAesTransactionManager",
basePackages = {"web.fileUpload.repo.db_aes.dao"}
)
public class DbAesDataSource {
@Primary
@Bean(name="dbAesDataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dbAesDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name="dbAesJdbcTemplate")
public JdbcTemplate dbAesJdbcTemplate(@Qualifier("dbAesDataSource") DataSource dbAesDataSource)
{
return new JdbcTemplate(dbAesDataSource);
}
@Bean(name="dbAesEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean dbAesEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("dbAesDataSource") DataSource dbAesDataSource) {
return builder
.dataSource(dbAesDataSource)
.packages("web.fileUpload.repo.db_aes.models")
.build();
}
@Bean(name = "dbAesTransactionManager")
public PlatformTransactionManager dbAesTransactionManager(
@Qualifier("dbAesEntityManagerFactory") EntityManagerFactory dbAesEntityManagerFactory) {
return new JpaTransactionManager(dbAesEntityManagerFactory);
}
}
AidcconfigDataSource
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "aidcconfigEntityManagerFactory",
transactionManagerRef = "aidcconfigTransactionManager",
basePackages = {"web.fileUpload.repo.aidcconfig.dao"}
)
public class AidcconfigDataSource {
@Bean(name="aidcconfigDataSource")
@ConfigurationProperties(prefix = "spring.secondDatasource")
public DataSource aidcconfigDataSource(){
return DataSourceBuilder.create().build();
}
@Bean(name="aidcconfigJdbcTemplate")
public JdbcTemplate aidcconfigJdbcTemplate(@Qualifier("aidcconfigDataSource") DataSource aidcconfigDataSource)
{
return new JdbcTemplate(aidcconfigDataSource);
}
@Bean(name="aidcconfigEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean aidcconfigEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("aidcconfigDataSource") DataSource aidcconfigDataSource) {
return builder
.dataSource(aidcconfigDataSource)
.packages("web.fileUpload.repo.aidcconfig.models")
.build();
}
@Bean(name = "aidcconfigTransactionManager")
public PlatformTransactionManager aidcconfigTransactionManager(
@Qualifier("aidcconfigEntityManagerFactory") EntityManagerFactory aidcconfigEntityManagerFactory) {
return new JpaTransactionManager(aidcconfigEntityManagerFactory);
}
}
这是我的错误:
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.3.5.RELEASE:run (default-cli) on
project testUpload: An exception occurred while running. null: InvocationTargetException: Error creating bean with
name 'fileDownloadController': Injection of autowired dependencies failed; nested exception is org.springframework
.beans.factory.BeanCreationException: Could not autowire field: private web.fileUpload.services.FileUploadService w
eb.fileUpload.controller.FileDownloadController.fileUploadService; nested exception is org.springframework.beans.fa
ctory.BeanCreationException: Error creating bean with name 'fileUploadService': Injection of autowired dependencies
failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org
.springframework.jdbc.core.JdbcTemplate web.fileUpload.services.FileUploadServiceImpl.dbAesJdbcTemplate; nested exc
eption is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springfr
amework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidat
e for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=tr
ue), @org.springframework.beans.factory.annotation.Qualifier(value=dbAesJdbcTemplate)} -> [Help 1]
如果我删除了 FileUploadServiceImpl 中的限定符,那么任何 jdbcTemplate 都将只连接到我的 db_aes 主数据库。如何使用 jdbcTemplate 访问我的第二个数据源?
以下是我使用的一些参考资料: Spring Boot, Spring Data JPA with multiple DataSources
https://www.infoq.com/articles/Multiple-Databases-with-Spring-Boot
Multiple DataSource and JdbcTemplate in Spring Boot (> 1.1.0)
试验#1 我注意到它无法创建 bean,因此我在 AidcconfigDataSource class 中放置了一些记录器。结果,我没有看到我的方法正在执行。因此,我假设应用程序没有读取我的 AidcconfigDataSource class.
我将配置文件夹从 java/config 移至 java/web/config:
现在我有另一个错误:
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.3.5.RELEASE:run (default-cli) on
project testUpload: An exception occurred while running. null: InvocationTargetException: Error creating bean with
name 'dataSourceInitializerPostProcessor': Injection of autowired dependencies failed; nested exception is org.spr
ingframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.beans.facto
ry.BeanFactory org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerPostProcessor.beanFactory; nested e
xception is org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'aidc
configDataSource' defined in class path resource [web/config/database/AidcconfigDataSource.class]: factory-bean ref
erence points back to the same bean definition -> [Help 1]
试用#2
我已经将我的 bean 名称从 aidcconfigDataSource 更改为 aidcconfigDS 并且与主数据源相同。另外,我在 application.properties 中添加了 "spring.jpa.open_in_view = false"。然而,另一个错误发生了。如何以正确的方式做到这一点?
2016-11-03 09:28:16.118 ERROR 11412 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.servic
e() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exce
ption is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springf
ramework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: dbAesTransa
ctionManager,aidcconfigTransactionManager] with root cause
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.
transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: dbAesTransactionMana
ger,aidcconfigTransactionManager
我认为 Spring Boot 正在尝试实例化 2 个具有相同名称的 bean:
aidcconfigDataSource
。
一个是你的配置 class AidcconfigDataSource.class
另一个是 bean:
@Bean(name="aidcconfigDataSource")
@ConfigurationProperties(prefix = "spring.secondDatasource")
public DataSource aidcconfigDataSource(){
return DataSourceBuilder.create().build();
}