Создайте источник данных фабрики соединений для использования в JdbcTemplate springboot

#spring-boot #datasource #jdbctemplate

Вопрос:

Не могли бы вы, пожалуйста, помочь мне создать мультисоединение datasource внутри springboot ? У меня будет много конфигураций баз данных, зарегистрированных в другой основной базе данных. Я не могу использовать источник данных, управляемый .properties spring, потому что у меня будет много настроек для подключения.

В конце концов, мне нужно JdbcTemplate отказаться от использования многих процедур.

Как создать фабрику источников данных весной для использования с JdbcTemplate? Я пробовал некоторые коды, но безуспешно;

Фабрика Соединений

 import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class ConfigDataSourceDynamic {

    private static Map<String,DataSource> mapDataSource;
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void init(){
        mapDataSource = new HashMap<String,DataSource>();
    }

    private DataSource createNewConnection(String nameConfig, String username, String password, String url, String driver){

        DataSource dataSource = DataSourceBuilder
                                .create()
                                .username(username)
                                .password(password)
                                .url(url)
                                .driverClassName(driver)
                                .build();

        mapDataSource.put(nameConfig, dataSource );
        return dataSource;
    }

    private DataSource getDataSource(String nameConfig, String nameConfig, String username, String password, String url, String driver){

        if( !mapDataSource.containsKey(nameConfig,  username, password,url, driver) )
            return createNewConnection(nameConfig);
        
        
        DataSource dataSource = mapDataSource.get(nameConfig);
        try{
            dataSource.getConnection().close();
        }catch(Exception e){
            e.printStackTrace();
        }

        return createNewConnection(tnsName);
    }

    public JdbcTemplate getJdbcTemplateDynamic(String nameConfig, String username, String password, String url, String driver) throws ApiReturnException{
        return new JdbcTemplate(getDataSource(nameConfig, username, password,url, driver));
    }

    
}
 

Выполнение кода

     @Autowired
    private ConfigDataSourceDynamic configDataSourceDynamic;

    public  Object testeMultiDBConfig() throws ApiReturnException{
        
        String nameConfig = // from table of configuration
        String username = // from table of configuration
        String password = // from table of configuration
        String url  = // from table of configuration
        String driver  = // from table of configuration

        JdbcTemplate jdbcTemplateTeste = configDataSourceDynamic.getJdbcTemplateDynamic(nameConfig, username, password,url, driver);

        List<Map<String, Object>> a = jdbcTemplateTeste.queryForList("select * from TESTE");

        a.forEach(System.out::println);

        return a;
    }
 

Я получил ошибки после 8,9 успешных подключений:

 oracle.net.ns.NetException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found

    at oracle.net.ns.NSProtocolNIO.negotiateConnection(NSProtocolNIO.java:284) NSProtocolNIO.java:284
    at oracle.net.ns.NSProtocol.connect(NSProtocol.java:340)  NSProtocol.java:340
    at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1596) T4CConnection.java:1596
    at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:588) T4CConnection.java:588
    at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:793) PhysicalConnection.java:793
    at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:57) T4CDriverExtension.java:57
    at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:747) OracleDriver.java:747
    at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:562) OracleDriver.java:562
    at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) DriverDataSource.java:138
 

Комментарии:

1. Я думаю, что это не весенняя проблема. Это проблема с сетевым подключением. Возможно, порты являются незаконными или порты заблокированы на стороне базы данных

2. @Alex Я получил 8,9 последовательных соединений, а затем получил ошибку. Есть ли другой способ создать фабрику соединений в springboot, чтобы использовать JdbcTemplate без источника данных bean?

3. Всегда ли параметры подключения одинаковы?

4. Нет, к сожалению, все параметры подключения являются определенной таблицей в базе данных, в зависимости от подключения, которое я собираюсь подключить и вызвать некоторые процедуры в определенной базе данных.

Ответ №1:

У меня есть лучшее решение 🙂 Я опубликую здесь…

Использование HikariConfig для управления пулом подключений

 import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class ConfigDataSourceDynamic {

    private static Map<String,HikariDataSource> mapDataSource;

    @PostConstruct
    public void init(){
        mapDataSource = new ConcurrentHashMap<String,HikariDataSource>();
    }

    private synchronized HikariDataSource createNewConnection(String tnsName,   String username, String password, String url, String driver){

        HikariConfig configHikari = new HikariConfig();
        configHikari.setUsername(username);
        configHikari.setPassword(password);
        configHikari.setJdbcUrl(url);
        configHikari.setDriverClassName(driver);

        HikariDataSource dataSource = new HikariDataSource(configHikari);
        mapDataSource.put(tnsName, dataSource );

        return dataSource;
    }


    private synchronized HikariDataSource getDataSource(String tnsName,   String username, String password, String url, String driver){

        if( !mapDataSource.containsKey(tnsName) )
            return createNewConnection(tnsName, username, password,url, driver);

        HikariDataSource dataSource = mapDataSource.get(tnsName);

        try{
           if(dataSource.isClosed()){
                return createNewConnection(tnsName);
           }else{
                return dataSource;
           }
        }catch(Exception e){
            e.printStackTrace();
        }

        return createNewConnection(tnsName);
    }

    public JdbcTemplate getJdbcTemplateDynamic(String tnsName,  String username, String password, String url, String driver){
        return new JdbcTemplate(getDataSource(tnsName, username, password,url, driver));
    }
    
}
 

Выполняется

  @Autowired
    private ConfigDataSourceDynamic configDataSourceDynamic;

    public  void testeMultiDBConfig() throws ApiReturnException{

        String nameConfig = // from table of configuration
        String username = // from table of configuration
        String password = // from table of configuration
        String url  = // from table of configuration
        String driver  = // from table of configuration

        JdbcTemplate jdbcTemplateTeste = configDataSourceDynamic
                                        .getJdbcTemplateDynamic(nameConfig, username, password,url, driver);
        
        for (int i = 0; i < 500; i  ) { // so many requests to over test
            jdbcTemplateTeste.execute("INSERT INTO TABLE1 ( COL ) VALUES ( 'VALUE')");
            List<Map<String, Object>> result = jdbcTemplateTeste.queryForList("SELECT * FROM TABLE1");
            result.forEach(System.out::println);
            jdbcTemplateTeste.execute("DELETE FROM TABLE1");
    
    }