You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Oracle UCP连接池环境下使用SQLExceptionTranslator?

解决Oracle UCP与Spring JdbcTemplate SQLExceptionTranslator兼容问题

问题根源

Oracle UCP抛出的oracle.ucp.UniversalConnectionPoolException继承自java.lang.Exception而非java.sql.SQLException,而Spring的SQLExceptionTranslator仅负责处理SQLException类型的异常。当UCP直接抛出连接池相关异常时,若强行将其传入SQLExceptionTranslator的方法中,就会触发ClassCastException。

解决方案

方案1:自定义SQLExceptionTranslator处理异常链中的UCP异常

针对SQL执行过程中被SQLException包装的UCP异常,我们可以扩展翻译器,先遍历异常链提取UCP异常,转换为SQLException后再交给默认逻辑处理:

import oracle.ucp.UniversalConnectionPoolException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SqlErrorCodesSQLExceptionTranslator;

public class UcpAwareSQLExceptionTranslator implements SQLExceptionTranslator {

    // 复用Spring默认的SQL错误码翻译器
    private final SQLExceptionTranslator defaultTranslator = new SqlErrorCodesSQLExceptionTranslator();

    @Override
    public DataAccessException translate(String task, String sql, SQLException ex) {
        // 遍历异常链,查找UCP异常
        Throwable current = ex;
        while (current != null) {
            if (current instanceof UniversalConnectionPoolException) {
                UniversalConnectionPoolException ucpEx = (UniversalConnectionPoolException) current;
                // 构造包含UCP异常信息的SQLException
                SQLException translatedSqlEx = new SQLException(
                        String.format("UCP连接池错误: %s", ucpEx.getMessage()),
                        ucpEx
                );
                // 交给默认翻译器生成对应的DataAccessException
                return defaultTranslator.translate(task, sql, translatedSqlEx);
            }
            current = current.getCause();
        }
        // 无UCP异常,直接用默认逻辑处理
        return defaultTranslator.translate(task, sql, ex);
    }
}

然后将该翻译器设置给JdbcTemplate:

JdbcTemplate jdbcTemplate = new JdbcTemplate(ucpDataSource);
jdbcTemplate.setExceptionTranslator(new UcpAwareSQLExceptionTranslator());

方案2:扩展JdbcTemplate捕获直接抛出的UCP异常

对于UCP在获取连接阶段直接抛出的UniversalConnectionPoolException(未被SQLException包装),需要扩展JdbcTemplate的执行逻辑,提前捕获并转换为Spring标准的DataAccessException:

import oracle.ucp.UniversalConnectionPoolException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.StatementCallback;

public class UcpJdbcTemplate extends JdbcTemplate {

    public UcpJdbcTemplate(DataSource dataSource) {
        super(dataSource);
        // 绑定自定义的SQL异常翻译器
        setExceptionTranslator(new UcpAwareSQLExceptionTranslator());
    }

    @Override
    protected <T> T execute(StatementCallback<T> action) throws DataAccessException {
        try {
            return super.execute(action);
        } catch (DataAccessException dae) {
            // 检查DataAccessException的根源是否为UCP异常
            Throwable cause = dae.getCause();
            if (cause instanceof UniversalConnectionPoolException) {
                throw new CannotGetJdbcConnectionException("无法从UCP连接池获取连接", cause);
            }
            throw dae;
        } catch (UniversalConnectionPoolException ucpEx) {
            // 直接捕获UCP异常,转换为Spring连接异常
            throw new CannotGetJdbcConnectionException("UCP连接池操作失败", ucpEx);
        }
    }
}

之后直接使用这个自定义的UcpJdbcTemplate即可,它会同时处理连接池异常和SQL执行异常。

方案3:全局异常处理(补充)

如果希望在应用层面统一处理UCP异常,可以添加全局异常处理器,将UniversalConnectionPoolException转换为Spring的DataAccessException:

import oracle.ucp.UniversalConnectionPoolException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.dao.DataAccessException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UniversalConnectionPoolException.class)
    public DataAccessException handleUcpException(UniversalConnectionPoolException ex) {
        return new CannotGetJdbcConnectionException("UCP连接池异常", ex);
    }
}

内容的提问来源于stack exchange,提问作者koli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:02:07