如何让Hibernate使用自定义连接执行Repository操作后立即关闭?
我们的应用基于Oracle数据库,存在部分审计相关表。针对这些表的所有数据变更操作必须伴随其他表中的审计条目,这通过设置连接属性由触发器自动实现(此方案为客户要求,无需讨论优劣)。但这些属性与用户相关,且会随时间或请求变化,而Oracle连接建立后无法修改属性,因此无法使用连接池。
目前我们的方案是不使用Hibernate连接池,自行创建连接:
Properties props = new Properties(); ...setproperties... Connection con = DriverManager.getConnection(connectionString, props); PreparedStatement stmt = con.prepareStatement(userSQL); con.executeUpdate(); ... clean up and close connection
但这种方式只能使用普通PreparedStatement,无法利用Hibernate Repository机制。现寻求方法:能否让Hibernate使用我们创建的特定连接执行repository.save()操作,且操作完成后立即关闭该连接,不放入Hibernate连接池?
可以通过Hibernate的Session和SessionFactory实现自定义连接的注入,核心思路是手动创建绑定自定义连接的Session,执行Repository操作后手动关闭Session和连接,具体步骤如下:
1. 创建自定义连接并绑定到Session
先生成带审计属性的自定义连接,再通过SessionFactory的配置指定该连接创建Session:
// 1. 构建带审计属性的自定义连接 Properties props = new Properties(); // 设置用户相关的审计属性(示例) props.put("oracle.jdbc.clientInfo.USER_ID", currentUserId); props.put("oracle.jdbc.clientInfo.OP_TIME", System.currentTimeMillis()); // 基础连接属性 props.put("user", dbUser); props.put("password", dbPwd); Connection customConn = DriverManager.getConnection(dbUrl, props); // 2. 创建绑定自定义连接的Session Session session = sessionFactory.withOptions() .connection(customConn) .openSession();
2. 关联Session到Repository执行操作
Hibernate Repository依赖Session上下文,可通过两种方式关联自定义Session:
方式一:Spring环境下绑定到线程上下文
如果是Spring Boot项目,利用SessionHolder将自定义Session绑定到当前线程,让Repository自动感知:
SessionHolder sessionHolder = new SessionHolder(session); try { // 绑定Session到线程上下文 TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder); // 执行Repository的save操作 yourEntityRepository.save(targetEntity); // 手动提交事务 session.getTransaction().commit(); } catch (Exception e) { // 异常回滚 if (session.getTransaction().isActive()) { session.getTransaction().rollback(); } throw e; } finally { // 解绑并关闭资源 TransactionSynchronizationManager.unbindResource(sessionFactory); session.close(); customConn.close(); // 手动关闭连接,不进入连接池 }
方式二:直接通过Session操作实体
无需Spring Repository注入时,可直接用Session完成实体保存,效果与repository.save()一致:
Transaction tx = null; try { tx = session.beginTransaction(); // 等价于repository.save()的操作 session.save(targetEntity); tx.commit(); } catch (Exception e) { if (tx != null && tx.isActive()) { tx.rollback(); } throw e; } finally { session.close(); customConn.close(); }
3. 核心注意事项
- 必须手动关闭自定义连接,Hibernate不会将手动传入的连接回收到内置连接池
- 若使用Spring的
@Transactional注解,需禁用该方法的自动事务管理,避免Spring从连接池获取默认连接 - 每次请求都要创建新的自定义连接和Session,确保连接属性与当前请求匹配
内容的提问来源于stack exchange,提问作者DigitalMachine

