dataSource or dataSourceClassName or jdbcUrl is required
mattshma opened this issue · comments
mattshma commented
在配置 springboot2 多数据源时,将 application-prod.yaml 从单一数据源配置修改为多数据源,修改后 datasource 的配置如下:
spring:
devtools:
restart:
enabled: false
livereload:
enabled: false
datasource:
primary:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://xxxxx
username: ***
password: ***
hikari:
auto-commit: false
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
secondary:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://yyyyyy
username: ***
password: ***
hikari:
auto-commit: false
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
而 DataSourceConfig.java 如下:
@Configuration
public class DataSourceConfiguration {
@Bean(name = "primaryDataSource")
@Primary
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSourceProperties() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
在运行时报错如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [config/LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1699)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:573)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:859)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:780)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:157)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:137)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5204)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1063)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:109)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:385)
修改 application-prod.yaml 配置如下:
spring:
devtools:
restart:
enabled: false
livereload:
enabled: false
datasource:
primary:
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://xxxxx
driver-class-name: com.mysql.jdbc.Driver
username: ***
password: ***
hikari:
auto-commit: false
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
secondary:
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://yyyyyy
driver-class-name: com.mysql.jdbc.Driver
username: ***
password: ***
hikari:
auto-commit: false
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
若不指定 driver-class-name
,会报错:java.lang.RuntimeException: Failed to get driver instance for jdbcUrl=jdbc:mysql
。
若报错:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
可以检查如下几点:
- PrimaryConfig.java 是否生效,主要查看:
- 是否有
@Primary
注解,若有该注解的话,会自动生成 entityManagerFactory。 - 是否 Secondary.Config.java 也配置了
@Primary
导致冲突。 - 是否有
@Configuration
注解,导致 PrimaryConfig.java 文件没生效。
- 是否有
- 报错的 domain 类,是否在
@primary
设置的entityManagerFactory
的packages()
搜索的目录中。 - 设置的
@EnableJpaRepositories
中的basePackages
用于配置 Repository 包位置,其路径是否正确。
若报错:
Caused by: java.lang.IllegalArgumentException: Not a managed type: class xxx
检查如下地方:
- entity 类是否有注解
@Entity
。 - entityManagerFactory 方法中是否指定了
packages("ENTITY_CLASS_PATH")
,如:builder .dataSource(primaryDataSource) .properties(getVendorProperties()) .packages("com.xyz.domain.primary") .persistenceUnit("primaryPersistenceUnit") .build();
- 如果 entity 是分在 domain.primary 和 domain.secondary 两个目录中,且 PrimaryConfig.java 配置的 packages 和 SecondaryConfig.java 配置的 packages 分别在这两个 domain 目录中,则 repository 也需要放在两个目录中,不能混在一起,即:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.xyz.repository.primary"} // 这里 repository 也需要放在 primary 目录中,否则加载时,会导致所有的 repository (包括 secondary repository 文件)也加载,进而导致报错。
)
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Autowired
private JpaProperties jpaProperties;
private Map<String, Object> getVendorProperties() {
return jpaProperties.getHibernateProperties(new HibernateSettings());
}
@Primary
@Bean(name = "entityManagerFactoryPrimary")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(primaryDataSource)
.properties(getVendorProperties())
.packages("com.xyz.domain.primary")
.persistenceUnit("primaryPersistenceUnit")
.build();
}
@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}
- 配置
@EntityScan(basePackages = {"com.xyz.domain.primary"})
。
mattshma commented
若报错:Can't call commit when autocommit=true
,则需要在 jdbcUrl: jdbc:mysql://xxxx?useUnicode=true&characterEncoding=utf&autoReconnect=true
后添加&relaxAutoCommit=true
。