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

拦截器中@Transactional是否复用Hikari连接池同连接?请求前置PL/SQL连接疑问

Spring Boot+Hikari连接池:请求前调用PL/SQL的连接复用问题

连接是否同一的核心逻辑

  • 无事务场景:如果拦截器里的PL/SQL调用没开启事务,每次都会从Hikari连接池新拿一个连接,执行完成后立即归还。这种情况下,和后续请求上下文里的连接几乎不可能是同一个,因为两者的连接获取是独立的。
  • 有事务场景:如果拦截器方法绑定了事务,连接会和当前线程绑定,后续同线程内的事务操作会复用这个连接。

JPA拦截器失效的原因

你尝试的JPA拦截器之所以没起作用,是因为它的触发时机是在EntityManager执行操作时,而你需要在HTTP请求刚进入系统(Controller处理前)就执行PL/SQL,这时候EntityManager可能还没被初始化,自然拦截不到。更合适的方案是用Spring的HandlerInterceptor或者Filter,它们是在请求进入Controller之前触发的,完全匹配你的需求。

@Transactional对连接复用的影响

在拦截器方法上添加@Transactional注解后:

  1. Spring会为当前请求线程绑定一个事务上下文,这个上下文会持有从Hikari池获取的单个连接。
  2. 后续请求中的DAO、JPA操作,如果使用默认的事务传播级别(REQUIRED),会直接复用这个已绑定的连接,不会从池里新拿。
  3. 例外情况:如果后续方法的事务传播级别是REQUIRES_NEW,会强制开启新事务,这时会从池里重新获取连接,不再复用拦截器里的那个。

实操示例(HandlerInterceptor方案)

1. 实现拦截器

@Component
public class PreRequestPLSQLInterceptor implements HandlerInterceptor {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    // 加@Transactional绑定当前线程的事务连接
    @Override
    @Transactional
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 调用PL/SQL存储过程
        jdbcTemplate.execute("CALL YOUR_STORED_PROCEDURE()");
        return true;
    }
}

2. 注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private PreRequestPLSQLInterceptor plsqlInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(plsqlInterceptor)
                .addPathPatterns("/**"); // 匹配所有需要拦截的请求路径
    }
}

验证连接是否同一的方法

可以在PL/SQL存储过程和请求的DAO方法中,查询数据库的会话ID并打印,对比两者是否一致:

  • Oracle示例:SELECT SYS_CONTEXT('USERENV','SESSIONID') FROM DUAL;
  • MySQL示例:SELECT CONNECTION_ID();

如果会话ID相同,说明复用了同一个连接;反之则是不同连接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:05:09