You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Hibernate执行ALTER TABLE命令时出现锁死问题求助

嘿,这个问题我碰到过类似的,咱们一步步来拆解解决:

1. 先搞清楚那个"idle in transaction"的SELECT来源

首先得弄明白那个挂着的事务到底在干嘛——Hibernate Search初始化时,会自动执行一些元数据查询(比如检查实体映射、索引表状态),这些查询可能因为配置问题没正确关闭事务,导致一直处于闲置状态。

  • 你可以用PostgreSQL的这个查询看详细信息:
    SELECT pid, query, state, query_start, xact_start FROM pg_stat_activity WHERE pid = 18499;
    
    重点看这个SELECT的具体内容,是不是关联了Hibernate Search的索引表(一般是hibernate_search_开头的表)。
  • 另外,Play Framework的会话默认和请求绑定,如果你在请求上下文外(比如初始化代码)获取会话,可能会触发隐式事务却没自动回收,导致事务挂着。
2. 先解决当前阻塞的紧急办法

先把那个闲置事务杀掉,让ALTER TABLE能继续执行:

SELECT pg_terminate_backend(18499);

放心,既然是idle in transaction状态,不会有正在执行的写操作,杀进程不会丢数据。

3. 从配置入手避免事务闲置

调整Hibernate Search的Schema管理策略

如果你已经确认数据库表结构和Hibernate Search的映射是匹配的,可以把自动DDL改成验证模式,这样就不会触发ALTER TABLE操作了:
hibernate.cfg.xml里添加:

<property name="hibernate.search.schema_management_strategy">validate</property>

这个设置会让Hibernate Search只验证现有表结构是否符合要求,不会自动修改表,从根源避免DDL阻塞问题。

检查事务管理配置

  • 你获取getCurrentSession()的方式,如果没有显式管理事务,可能会导致事务一直开着。尽量用事务包裹初始化代码:
    SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
    try (Session session = sessionFactory.getCurrentSession()) {
        Transaction tx = session.beginTransaction();
        session.flush();
        tx.commit(); // 一定要提交或回滚事务
    } catch (Exception e) {
        // 异常时回滚
        if (session.getTransaction().isActive()) {
            session.getTransaction().rollback();
        }
        e.printStackTrace();
    }
    
  • 检查hibernate.connection.autocommit配置,如果设为false,每个查询都会开启事务,没显式提交就会挂着。如果你的业务允许,可以暂时设为true测试(注意这会影响其他事务逻辑,需谨慎)。
4. 规范Play Framework中的会话使用

Play的Hibernate会话默认和请求生命周期绑定,如果你在应用启动时(比如onStart()方法)执行初始化逻辑,一定要手动管理事务,避免会话泄漏:

public class AppStartup extends GlobalSettings {
    @Override
    public void onStart(Application app) {
        SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
        try (Session session = sessionFactory.openSession()) { // 这里用openSession而非getCurrentSession,避免绑定到请求上下文
            Transaction tx = session.beginTransaction();
            // 执行Hibernate Search初始化操作,比如手动构建索引
            tx.commit();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

openSession()代替getCurrentSession(),可以避免和请求上下文绑定,更灵活地管理事务生命周期。

5. 考虑升级依赖版本

你用的Hibernate 5.2.12.Final和PostgreSQL驱动42.1.4都是比较老的版本,里面可能存在事务管理的bug:

  • Hibernate 5.2.x系列可以升级到最新的5.2.22.Final,或者直接跳转到更稳定的5.4.x版本;
  • PostgreSQL驱动升级到42.2.x及以上版本,新版本对事务的处理更严谨。

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

火山引擎 最新活动