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

如何在GlassFish中编程实现@Resource与@PersistenceContext的功能?

问题描述

我在使用带有多个JDBC连接池的GlassFish服务器,想要为每个JDBC连接单独创建EntityManagerFactory。目前用以下代码可以成功创建EntityManagerFactory:

Map props = new HashMap();
props.put(PersistenceUnitProperties.JTA_DATASOURCE, <my jdbc datasource>);
Persistence.createEntityManagerFactory(<persistence unit name>, props);

但没法结合UserTransaction实现事务的开启、提交和回滚,连entityManager.getTransaction().begin/commit/rollback也不正常——出错时记录还是会持久化到数据库。

用注入方式获取UserTransaction和EntityManager时:

@Resource
UserTransaction utx1;
@PersistenceContext(unitName = <persistence unit name>)
private EntityManager em1;

utx1.begin()、utx1.commit()能完美控制EntityManager,但没法切换使用服务器上配置的多个JDBC连接池。我试着在@PersistenceContext里加properties指定数据源,也没生效:

@Resource
UserTransaction utx1;

@PersistenceContext(
        properties = {@PersistenceProperty(name=PersistenceUnitProperties.JTA_DATASOURCE, value="ORCLH_MARMA")}, 
        unitName = "MINLO")
private EntityManager em1; 

我的问题是:能不能以编程方式实现上述注入代码的功能?


解决方案

1. 优先通过多持久化单元配置实现(最稳妥)

GlassFish容器优先读取persistence.xml的持久化单元定义,你可以为每个JDBC连接池单独定义一个持久化单元,直接绑定对应的JTA数据源:

<!-- persistence.xml -->
<persistence-unit name="MINLO_ORCLH_MARMA" transaction-type="JTA">
    <jta-data-source>ORCLH_MARMA</jta-data-source>
    <class>com.yourpackage.YourEntity</class>
    <!-- 其他配置:提供商、缓存等 -->
</persistence-unit>

<persistence-unit name="MINLO_OTHER_DS" transaction-type="JTA">
    <jta-data-source>OTHER_JDBC_POOL</jta-data-source>
    <class>com.yourpackage.YourEntity</class>
</persistence-unit>

之后注入时直接指定对应单元名,就能同时保留事务控制和多数据源切换能力:

@Resource
UserTransaction utx;

// 使用ORCLH_MARMA连接池的EntityManager
@PersistenceContext(unitName = "MINLO_ORCLH_MARMA")
private EntityManager emOrcl;

// 使用另一个连接池的EntityManager
@PersistenceContext(unitName = "MINLO_OTHER_DS")
private EntityManager emOther;

2. 编程式实现容器管理的JTA EntityManager

如果一定要用代码手动实现类似注入的效果,不能直接用Persistence.createEntityManagerFactory(这会创建本地事务型的EMF),而是要通过JNDI获取容器管理的JTA型EntityManagerFactory,再绑定UserTransaction:

// 获取容器的UserTransaction
UserTransaction utx = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");

// 通过JNDI获取对应持久化单元的EntityManagerFactory
// GlassFish中JNDI格式通常为java:comp/env/persistence/[持久化单元名]
EntityManagerFactory emf = (EntityManagerFactory) 
    new InitialContext().lookup("java:comp/env/persistence/MINLO_ORCLH_MARMA");

// 创建JTA类型的EntityManager
EntityManager em = emf.createEntityManager();

// 事务控制逻辑
try {
    utx.begin();
    em.persist(yourEntity);
    utx.commit();
} catch (Exception e) {
    // 异常时回滚事务
    if (utx.getStatus() == Status.STATUS_ACTIVE) {
        try {
            utx.rollback();
        } catch (Exception rollbackEx) {
            rollbackEx.printStackTrace();
        }
    }
    throw new RuntimeException("事务处理失败", e);
} finally {
    // 手动关闭应用管理的EntityManager
    em.close();
}

3. 为什么@PersistenceContext加properties没生效?

GlassFish的@PersistenceContext注解的properties参数不支持覆盖persistence.xml中定义的jta-data-source——容器会优先读取持久化单元的静态配置,所以这种方式无法实现数据源切换,必须通过定义多个持久化单元解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:50:40