Dynamic datasource in Spring boot JPA

不问归期 提交于 2019-12-18 05:23:10

问题


I have an application that need to connect to few different schema's but everything of same type (ORACLE). The decision of which schema comes from UI.

if User selects schema1, then entity should persist in Schema1, if selects other, then it should be in the selected other schema.

Am using Spring boot + Hibernate with the dependency "spring-boot-starter-data-jpa"

I have created a datasource class like below so that i can change the "schemaName" in the datasource object everytime before invoking the data layer.

@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;
    }

}

My problem is during the startup, the "HibernateJpaAutoConfiguration" tries creating sessionfactory.During creation it tries to check connection with the datasource But as schemaName is null in the startup, my SchemaDatasource returns null connection with which application bootstrap is failed.

is there a way to handle this. Am expecting similar to SessionFactory withnooptions in hibernate.

In case of RoutingDatasource also, i have to set defaultDatasource.

Spring boot version: 1.5.9.RELEASE

回答1:


Here is my implementation of 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);
    }
}

Here is my configuration

@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;
    }

}

Here is 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


来源:https://stackoverflow.com/questions/48744973/dynamic-datasource-in-spring-boot-jpa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!