Welcome to JiKe DevOps Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
769 views
in Technique[技术] by (71.8m points)

hibernate - Dynamic datasource in Spring boot JPA

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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

Please log in or register to answer this question.

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to JiKe DevOps Community for programmer and developer-Open, Learning and Share
...