拦截器中@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注解后:
- Spring会为当前请求线程绑定一个事务上下文,这个上下文会持有从Hikari池获取的单个连接。
- 后续请求中的DAO、JPA操作,如果使用默认的事务传播级别(
REQUIRED),会直接复用这个已绑定的连接,不会从池里新拿。 - 例外情况:如果后续方法的事务传播级别是
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
相关产品推荐
相关产品推荐

