Payara 5事务上下文用Hazelcast时EntityManager被关闭问题求助
问题根源
Payara集成的Hazelcast租户控制组件(fish.payara.nucleus.hazelcast.PayaraHazelcastTenant)会将应用的请求/事务上下文附加到Hazelcast操作上。当Hazelcast操作执行完成后,该组件会尝试提前关闭上下文资源,而此时事务上下文尚未结束,导致容器错误地关闭了仍在使用的EntityManager,触发java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager异常。
可行解决方案
1. 禁用Payara Hazelcast的租户上下文传播
通过配置禁用租户上下文向Hazelcast操作的传播,避免Payara在Hazelcast操作后触发不必要的资源清理:
- 使用Payara管理命令(asadmin)执行:
asadmin set configs.config.server-config.hazelcast.tenant-propagation-enabled=false - 或者直接编辑
domain.xml,找到<hazelcast>配置块,添加或修改参数:<hazelcast> <tenant-propagation-enabled>false</tenant-propagation-enabled> <!-- 其他Hazelcast配置 --> </hazelcast>
修改后重启Payara服务器,该配置会阻止Payara将租户上下文附加到Hazelcast操作,从而避免提前清理EntityManager。
2. 使用独立Hazelcast实例替代Payara集成版
如果应用不需要Payara提供的租户管理功能,可以完全禁用Payara内置的Hazelcast模块,改用独立的Hazelcast依赖:
- 禁用Payara内置Hazelcast模块:
asadmin disable-module hazelcast - 在项目依赖中添加独立的Hazelcast库(以Maven为例):
<dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast</artifactId> <version>4.2</version> <!-- 与当前使用的版本匹配 --> </dependency> - 自行通过
hazelcast.xml配置Hazelcast实例,完全脱离Payara的上下文管理,避免容器干涉资源生命周期。
3. 调整事务内Hazelcast操作的上下文控制
如果必须保留Payara的租户功能,可以通过事务同步机制确保Hazelcast操作在事务完成后执行:
- 在事务方法中,使用
TransactionSynchronizationRegistry注册同步回调,将Hazelcast操作延迟到事务提交阶段:@Inject private TransactionSynchronizationRegistry tsr; @Transactional public void yourTransactionalMethod() { // 核心业务逻辑... // 注册事务提交后执行的Hazelcast操作 tsr.registerInterposedSynchronization(new TransactionSynchronization() { @Override public void afterCompletion(int status) { if (status == Status.STATUS_COMMITTED) { // 在此执行Hazelcast IMap操作 hazelcastInstance.getMap("statefulRoomSOSChangeListenerMap").put(key, value); } } @Override public void beforeCompletion() {} @Override public void afterBegin() {} @Override public void beforeCommit() {} @Override public void afterRollback() {} }); }
这种方式确保Hazelcast操作在事务提交后执行,此时EntityManager已完成生命周期,不会出现提前关闭的冲突。
验证方案有效性
完成配置或代码修改后,在事务方法中访问Hazelcast IMap,检查是否再出现EntityManager已关闭的异常,同时确保事务逻辑和Hazelcast操作都能正常执行。
内容的提问来源于stack exchange,提问作者drame

