Glassfish+EJB+JPA(Hibernate)环境下数据库插入失败问题求助
我碰到过好几个类似的场景,结合你描述的情况——查询正常但插入失效,换EclipseLink就没问题,核心问题肯定出在Hibernate和Glassfish JTA事务的适配上,给你几个针对性的排查和解决步骤:
1. 先确认EJB的事务注解配置是否正确
查询正常说明EntityManager能正常连接数据源,但插入操作必须依赖事务支持。Hibernate在JTA环境下,只有在活跃事务中执行的persist操作,才会在事务提交时自动刷入数据库。
- 检查你的
addMessage()方法所在的EBean,是否被错误设置了非事务性的注解。比如无状态Bean默认是@TransactionAttribute(TransactionAttributeType.REQUIRED),但如果被手动改成NOT_SUPPORTED或SUPPORTS,就会导致操作脱离事务环境。 - 建议显式给
addMessage()标注事务注解,确保它运行在JTA事务中:@Stateless public class MessageBean { @PersistenceContext(unitName = "YourPU") private EntityManager em; @TransactionAttribute(TransactionAttributeType.REQUIRED) public void addMessage(Message message) { em.persist(message); // 别手动调用em.flush()!JTA事务提交时Hibernate会自动处理刷库逻辑 } }
2. 检查persistence.xml中的Hibernate JTA配置
这是最容易踩坑的点——EclipseLink默认对Glassfish的JTA适配很好,但Hibernate需要显式指定JTA平台才能正确和Glassfish的事务管理器交互。
打开你的persistence.xml,确保配置了以下关键属性:
<persistence-unit name="YourPU" transaction-type="JTA"> <jta-data-source>jdbc/YourDataSource</jta-data-source> <properties> <!-- 必须指定Glassfish对应的JTA平台,这是核心修复点! --> <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/> <property name="hibernate.transaction.coordinator_class" value="jta"/> <!-- 可选:开启SQL日志,方便确认persist语句是否真的执行了 --> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> </properties> </persistence-unit>
如果没配置hibernate.transaction.jta.platform,Hibernate可能无法识别Glassfish的JTA事务,导致persist的内容永远不会被提交到数据库。
3. 排查是否有隐藏异常导致事务回滚
有时候看起来方法正常执行,但其实内部抛出了未捕获的异常,EJB容器会自动回滚事务,导致插入失效。
- 在
addMessage()里加个异常捕获,打印堆栈信息:public void addMessage(Message message) { try { em.persist(message); System.out.println("Persisted message with ID: " + message.getId()); // 确认代码执行到这一步 } catch (Exception e) { e.printStackTrace(); throw new EJBException("Failed to add message", e); // 抛出异常让容器处理事务回滚逻辑 } } - 同时去Glassfish的服务器日志(
domain/logs/server.log)里搜transaction rolled back之类的关键词,看看有没有事务回滚的记录。
4. 确认EntityManager的注入方式
一定要用@PersistenceContext注入EntityManager,手动创建的EntityManager不会参与JTA事务,自然无法提交插入操作:
// 正确姿势 @PersistenceContext(unitName = "YourPU") private EntityManager em; // 错误姿势(千万别这么做!) private EntityManager em = Persistence.createEntityManagerFactory("YourPU").createEntityManager();
5. 检查Hibernate和Glassfish的版本兼容性
如果上面的步骤都没解决,可能是版本不兼容导致的。比如Glassfish 5.x推荐搭配Hibernate 5.4及以上版本,旧版本的Hibernate对Glassfish的JTA支持可能有bug。可以查一下Glassfish的官方文档,确认你用的Hibernate版本是否在兼容范围内。
按照上面的步骤逐一排查,应该能解决插入不生效的问题——我之前帮同事排查过几乎一样的场景,最后就是因为没配置JTA平台导致的。
内容的提问来源于stack exchange,提问作者Eugene

