Home > Software design >  How to use the new database credentials to connect with database without restarting the application
How to use the new database credentials to connect with database without restarting the application

Time:02-25

I have a Spring application which connects with a database using ComboPooledDataSource, LocalContainerEntityManagerFactoryBean and JpaTransactionManager. The application works fine. Following is my configuration.

<!-- DataSource JavaConfig -->

@Configuration
public class DataSourceConfig
{
@Bean
public DataSource dataSource()
{
    try {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(getUsername());
        dataSource.setPassword(getPassword());
        dataSource.setDriverClass(driverClassName);
        dataSource.setJdbcUrl(jdbcUrl);
        dataSource.setMinPoolSize(minPoolSize);
        dataSource.setMaxPoolSize(maxPoolSize);
        dataSource.setCheckoutTimeout(checkoutTimeout);
        dataSource.setMaxIdleTime(maxIdleTime);
        dataSource.setIdleConnectionTestPeriod(idleConnectionTestPeriod);
        dataSource.setAcquireRetryAttempts(acquireRetryAttempts);
        dataSource.setAcquireRetryDelay(acquireRetryDelay);
        return dataSource;
    } catch (Exception ex) {
        LOGGER.error("Error occurred while initializing datasource ", ex);
    }
    return null;
  }
}

<!-- Transaction Manager -->
<bean id="transactionManager" >
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="dataSource" ref="dataSource"/>
</bean>


<!-- Entity manager factory -->
<bean id="entityManagerFactory"  depends-on="dbMigrationService">
    <property name="dataSource" ref="dataSource"/>
    <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
    <property name="jpaVendorAdapter">
        <bean >
            <property name="showSql" value="${hibernate.showSql}"/>
            <property name="databasePlatform" value="${hibernate.dialect}"/>
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <!-- batch writing -->
            <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
            <prop key="hibernate.order_inserts">${hibernate.order_inserts}</prop>
            <prop key="hibernate.order_updates">${hibernate.order_updates}</prop>
            <prop key="hibernate.enable_lazy_load_no_trans">true</prop>
        </props>
    </property>
</bean>

But my database password is being rotated frequently using Hashicorp vault and I've the new password. Now i need to use the new password to make connections with the database, also i need to do this without restarting the application. So is it possible to change the database credentials used in the datasource while application is running? If yes What should i need to do for this? Can someone help me with this? Thanks.

CodePudding user response:

I think that you need to do something like that.

public class DataSourceStateListener {
    @Autowired
    private DataSource dataSource;

    @EventListener
    public void changeDataSourceCredentials(DBCredentialsEvent event) {
        dataSource.setPassword(event.getPassword());
    } 
}

DBCredentialsEvent should be fired when new credentials has been requested from Vault.

@Autowired
private ApplicationEventPublisher eventPublisher;

eventPublisher(new DBCredentialsEvent(vaultPassword));

I found these lines of code in AbstractComboPooledDataSource.

public void setUser( String user ) {
    if ( diff( dmds.getUser(), user ) ) {
        dmds.setUser( user ); 
        this.resetPoolManager( false );
    }
}

public void setPassword( String password ) { 
    if ( diff( dmds.getPassword(), password ) ) {
        dmds.setPassword( password ); 
        this.resetPoolManager( false );
    }
}

So, it seems that changing either database user or password does reset the pool manager as well. Anyway, the behaviour should be tested before going to production.

  • Related