Spring 启动 JPA 中的动态数据源
Dynamic datasource in Spring boot JPA
我有一个应用程序需要连接到几个不同的模式,但所有类型都相同 (ORACLE)。哪个模式的决定来自 UI。
如果用户选择 schema1,那么实体应该保留在 Schema1 中,如果选择其他,那么它应该在选择的其他模式中。
我正在使用 Spring 引导 + 具有依赖性的 Hibernate "spring-boot-starter-data-jpa"
我创建了一个数据源 class,如下所示,这样我就可以在每次调用数据层之前更改数据源对象中的 "schemaName"。
@Component
public class SchemaDatasource extends AbstractDataSource {
private String schemaName;
@Autowired
private DSManager dsm;
public void setSchemaName(String schemaName) {
this.schemaName = schemaName;
}
@Override
public Connection getConnection() throws SQLException {
if (schemaName!= null)
return dsm.getConnection(schemaName);
else
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
if (schemaName!= null)
return dsm.getConnection(schemaName);
else
return null;
}
}
我的问题是在启动过程中,"HibernateJpaAutoConfiguration" 尝试创建 sessionfactory.During 创建它尝试检查与数据源的连接但是由于启动时 schemaName 为空,我的 SchemaDatasource returns与应用程序 bootstrap 的空连接失败。
有没有办法解决这个问题。我期待类似于 SessionFactory withnooptions in hibernate。
对于 RoutingDatasource,我也必须设置 defaultDatasource。
Spring boot version: 1.5.9.RELEASE
这是我对 DataSource 的实现
public class DataSourceManager implements DataSource {
private Map<String, DataSource> dataSources = new HashMap<>();
private DataSource dataSource;
public DataSourceManager() {
}
public DataSourceManager(DataSource dataSource) {
this.dataSource = dataSource;
}
public void add(String name, DataSource dataSource) {
dataSources.put(name, dataSource);
}
public void switchDataSource(String name) {
dataSource = dataSources.get(name);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
dataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
dataSource.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return dataSource.getParentLogger();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return dataSource.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return dataSource.isWrapperFor(iface);
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return dataSource.getConnection(username, password);
}
}
这是我的配置
@Configuration
public class DataSourceConfig {
@Autowired
private Environment env;
public DataSource makeDataSource(String name) {
return DataSourceBuilder.create()
.driverClassName(env.getProperty("spring.datasource." + name + ".driver-class-name"))
.url(env.getProperty("spring.datasource." + name + ".url")).build();
}
@Bean
public DataSource dataSource() {
DataSourceManager dataSourceManager = new DataSourceManager();
dataSourceManager.add("test1", makeDataSource("test1"));
dataSourceManager.add("test2", makeDataSource("test2"));
dataSourceManager.switchDataSource("test1");
return dataSourceManager;
}
}
这里是application.yml
spring:
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
datasource:
test1:
name: test2
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: h2
password: h2
test2:
name: test1
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: h2
password: h2
我有一个应用程序需要连接到几个不同的模式,但所有类型都相同 (ORACLE)。哪个模式的决定来自 UI。
如果用户选择 schema1,那么实体应该保留在 Schema1 中,如果选择其他,那么它应该在选择的其他模式中。
我正在使用 Spring 引导 + 具有依赖性的 Hibernate "spring-boot-starter-data-jpa"
我创建了一个数据源 class,如下所示,这样我就可以在每次调用数据层之前更改数据源对象中的 "schemaName"。
@Component
public class SchemaDatasource extends AbstractDataSource {
private String schemaName;
@Autowired
private DSManager dsm;
public void setSchemaName(String schemaName) {
this.schemaName = schemaName;
}
@Override
public Connection getConnection() throws SQLException {
if (schemaName!= null)
return dsm.getConnection(schemaName);
else
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
if (schemaName!= null)
return dsm.getConnection(schemaName);
else
return null;
}
}
我的问题是在启动过程中,"HibernateJpaAutoConfiguration" 尝试创建 sessionfactory.During 创建它尝试检查与数据源的连接但是由于启动时 schemaName 为空,我的 SchemaDatasource returns与应用程序 bootstrap 的空连接失败。
有没有办法解决这个问题。我期待类似于 SessionFactory withnooptions in hibernate。
对于 RoutingDatasource,我也必须设置 defaultDatasource。
Spring boot version: 1.5.9.RELEASE
这是我对 DataSource 的实现
public class DataSourceManager implements DataSource {
private Map<String, DataSource> dataSources = new HashMap<>();
private DataSource dataSource;
public DataSourceManager() {
}
public DataSourceManager(DataSource dataSource) {
this.dataSource = dataSource;
}
public void add(String name, DataSource dataSource) {
dataSources.put(name, dataSource);
}
public void switchDataSource(String name) {
dataSource = dataSources.get(name);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
dataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
dataSource.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return dataSource.getParentLogger();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return dataSource.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return dataSource.isWrapperFor(iface);
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return dataSource.getConnection(username, password);
}
}
这是我的配置
@Configuration
public class DataSourceConfig {
@Autowired
private Environment env;
public DataSource makeDataSource(String name) {
return DataSourceBuilder.create()
.driverClassName(env.getProperty("spring.datasource." + name + ".driver-class-name"))
.url(env.getProperty("spring.datasource." + name + ".url")).build();
}
@Bean
public DataSource dataSource() {
DataSourceManager dataSourceManager = new DataSourceManager();
dataSourceManager.add("test1", makeDataSource("test1"));
dataSourceManager.add("test2", makeDataSource("test2"));
dataSourceManager.switchDataSource("test1");
return dataSourceManager;
}
}
这里是application.yml
spring:
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
datasource:
test1:
name: test2
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: h2
password: h2
test2:
name: test1
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: h2
password: h2