Druid数据源配置热更新报错 UnsupportedOperationException

后续补充新的报错说明:

最新修改后的完整填充配置截图:

        

        数据源配置热更新失败场景:原数据源类型与切换后的数据源类型不一致时,比如之前绑定的是oracle数据库,通过接口更换为mysql数据库;

(1)数据库类型未进行手动设置

2024-07-02 16:33:38.754 ERROR [Druid-ConnectionPool-Create-2048013503] com.alibaba.druid.pool.DruidDataSource -| create connection thread interrupted, url: jdbc:oceanbase://127.0.0.1:2883/dbtrade?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&socketTimeout=300000
java.lang.InterruptedException: null
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014) ~[?:1.8.0_362]
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048) ~[?:1.8.0_362]
	at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2921) ~[druid-1.2.20.jar!/:?]

        之前程序配置数据源配置时未进行手动配置,但是druidDataSource内部会根据url进行设置,如图:(并且如果已经初始化完成了,下次再执行init()方法,并不会再对dbTypeName重新初始化,所以每次在使用的地方需要进行更新,或者直接赋值空串,让druidDataSource自动去赋值)

(2)驱动的Driver对象未进行覆盖

java.sql.SQLException: not support oracle driver 8.2
    at com.alibaba.druid.pool.DruidDataSource.initCheck(DruidDataSource.java:1294)......
    ......

        数据源类型发生改变之后,若此对象不进行修改,则无法正确获取数据库连接,druidDataSource初始化会失败,如图:(笔者的解决办法就是在配置数据源处将该对象置为null,使得druidDataSource下次初始化时会重新生成该对象)

(3)数据库连接池执行 ValidationQuery 失败

        与前面两点同理;配置数据源时将 validConnectionChecker对象置为null,druidDataSource初始化时重新生成该对象;

分割线

=======================================================================

在应用中需要修改数据源配置信息的场景可能比较少,但是如果有需要按照以下步骤进行操作:

1.项目中druidDataSource已经初始化完成;

2.直接对该数据源进行配置填充时会报错,具体原因为:

com.alibaba.druid.pool.DruidAbstractDataSource 中数据源的配置属性,都会判断inited,如果为true,不允许修改

// 不管是dataSource.setUrl还是setUserName等方法
// 在其内部都有对是否初始化状态进行判断,如下:

public void setUsername(String username) {
    if (StringUtils.equals(this.username, username)) {
        return;
    }

    if (inited) {
        throw new UnsupportedOperationException();
    }

    this.username = username;
}

        若数据源在之前已经进行过初始化了,那么就会报错;解决办法就是将初始化状态设置为false,官方提供的方法是  restart();

3.在配置填充之前调用 restart() 方法;

druid init的时候设置为true(即初始化后便不允许变更),即使执行close方法也无法修改配置属性(close方法并不会设置inited = false),只有执行restart才能修改配置。但是restart 会执行close方法不会执行init方法。所以现在如果想热加载druid的配置需要先执行restart(restart 会将inited 设置为false),然后修改配置后再执行init方法,如下:

dataSource.restart();

其源码为:

public void restart(Properties properties) throws SQLException {
    lock.lock();
    try {
        if (activeCount > 0) {
            throw new SQLException("can not restart, activeCount not zero. " + activeCount);
        }
        if (LOG.isInfoEnabled()) {
            LOG.info("{dataSource-" + this.getID() + "} restart");
        }

        this.close();
        this.resetStat();
        this.inited = false;
        this.enable = true;
        this.closed = false;

        if (properties != null) {
            configFromProperties(properties);
        }
    } finally {
        lock.unlock();
    }
}

4.在填充完配置之后,再调用init() 方法即可;

dataSource.init();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值