如何解决仅当 EJB 调用中捕获到 RuntimeException 时,才阻止标记为回滚的 JTA 事务
我在参与 JTA 事务的 Wildfly 上部署了有状态 EJB 3。此 EJB 是 Keycloak 的扩展用户提供程序。
其中一个 EJB 操作在某个时间点被调用,并可能产生 RuntimeException。我需要提交全局事务,所以我在 ejb 方法中添加了一个 try-catch 块。
@Stateful
@Local(EjbUserStorageProvider.class)
public class EjbUserStorageProvider implements UserStorageProvider,UserLookupProvider,UserRegistrationProvider,UserQueryProvider,CredentialInputUpdater,CredentialInputValidator,OnUserCache
{
...
@Override
public int getUsersCount(RealmModel realm) {
try {
Object count = em.createNamedQuery("getUserCount").getSingleResult();
return ((Number)count).intValue();
} catch(RuntimeException e) {
e.printstacktrace();
return 0;
}
}
}
问题是,尽管捕获了异常,事务还是回滚了。
这是有问题的地方:
org.keycloak.models.utils.KeycloakModelUtils
public static void runJobInTransaction(KeycloakSessionFactory factory,KeycloakSessionTask task) {
KeycloakSession session = factory.create();
KeycloakTransaction tx = session.getTransactionManager();
try {
tx.begin();
task.run(session);
if (tx.isActive()) {
if (tx.getRollbackOnly()) {
tx.rollback();
} else {
tx.commit();
}
}
} catch (RuntimeException re) {
if (tx.isActive()) {
tx.rollback();
}
throw re;
} finally {
session.close();
}
}
出于某种原因,tx.getRollbackOnly()
返回 true,因此 JTA 事务被回滚。
如何防止事务被标记为仅回滚?
更新
我尝试使用 @Transactional 但被忽略了:
@Transactional(value = Transactional.TxType.NEVER,dontRollbackOn = {RuntimeException.class,PersistenceException.class})
@Override
public int getUsersCount(RealmModel realm) {
我也使用了 @TransactionAttribute(NOT_SUPPORTED)
但在这种情况下 Keycloak 无法启动:
09:36:30,784 ERROR [org.jboss.as.ejb3.invocation] (ServerService Thread Pool -- 51) WFLYEJB0034: EJB Invocation Failed on component EjbUserStorageProvider for method public int es.mma.edm.keycloak.storage.user.EjbUserStorageProvider.getUsersCount(org.keycloak.models.RealmModel): javax.ejb.ConcurrentAccesstimeoutException: WFLYEJB0228: EJB 3.1 FR 4.3.14.1 concurrent access timeout on EjbUserStorageProvider - Could not obtain lock within 5000 MILLISECONDS
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.stateful.StatefulSessionSynchronizationInterceptor.processInvocation(StatefulSessionSynchronizationInterceptor.java:94)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ee@7.2.0.GA-redhat-00005//org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:40)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
at org.jboss.as.ee@7.2.0.GA-redhat-00005//org.jboss.as.ee.component.interceptors.ComponentdispatcherInterceptor.processInvocation(ComponentdispatcherInterceptor.java:52)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.stateful.StatefulComponentInstanceInterceptor.processInvocation(StatefulComponentInstanceInterceptor.java:59)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInNoTx(CMTTxInterceptor.java:216)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.tx.CMTTxInterceptor.notSupported(CMTTxInterceptor.java:337)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:142)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:47)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.deployment.processors.StartupAwaitInterceptor.processInvocation(StartupAwaitInterceptor.java:22)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ejb3@7.2.0.GA-redhat-00005//org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:67)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.as.ee@7.2.0.GA-redhat-00005//org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:60)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:438)
at org.wildfly.security.elytron-private@1.6.1.Final-redhat-00001//org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:619)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:57)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation@1.5.1.Final-redhat-1//org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
at org.jboss.as.ee@7.2.0.GA-redhat-00005//org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:198)
at org.jboss.as.ee@7.2.0.GA-redhat-00005//org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:185)
at org.jboss.as.ee@7.2.0.GA-redhat-00005//org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:81)
at deployment.edm-keycloak-user-storage.jar//es.mma.edm.keycloak.storage.user.EjbUserStorageProvider$$$view1.getUsersCount(UnkNown Source)
at org.keycloak.keycloak-services@4.8.3.Final-redhat-00001//org.keycloak.storage.UserStorageManager.getUsersCount(UserStorageManager.java:453)
at org.keycloak.keycloak-model-infinispan@4.8.3.Final-redhat-00001//org.keycloak.models.cache.infinispan.UserCacheSession.getUsersCount(UserCacheSession.java:543)
at org.keycloak.keycloak-model-infinispan@4.8.3.Final-redhat-00001//org.keycloak.models.cache.infinispan.UserCacheSession.getUsersCount(UserCacheSession.java:548)
at org.keycloak.keycloak-services@4.8.3.Final-redhat-00001//org.keycloak.services.managers.ApplianceBootstrap.isNoMasterUser(ApplianceBootstrap.java:55)
at org.keycloak.keycloak-services@4.8.3.Final-redhat-00001//org.keycloak.services.resources.KeycloakApplication$2.run(KeycloakApplication.java:168)
at org.keycloak.keycloak-server-spi-private@4.8.3.Final-redhat-00001//org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
at org.keycloak.keycloak-services@4.8.3.Final-redhat-00001//org.keycloak.services.resources.KeycloakApplication.<init>(KeycloakApplication.java:164)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:154)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.spi.ResteasyProviderFactory.createProviderInstance(ResteasyProviderFactory.java:2757)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.spi.ResteasyDeployment.createApplication(ResteasyDeployment.java:363)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.spi.ResteasyDeployment.startInternal(ResteasyDeployment.java:276)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:88)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.plugins.server.servlet.ServletContainerdispatcher.init(ServletContainerdispatcher.java:119)
at org.jboss.resteasy.resteasy-jaxrs@3.6.1.SP2-redhat-00001//org.jboss.resteasy.plugins.server.servlet.HttpServletdispatcher.init(HttpServletdispatcher.java:36)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:117)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.security.RunAsLifecycleInterceptor.init(RunAsLifecycleInterceptor.java:78)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:103)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start(ManagedServlet.java:303)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.ManagedServlet.createServlet(ManagedServlet.java:143)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:583)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:554)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at io.undertow.servlet@2.0.15.Final-redhat-00001//io.undertow.servlet.core.DeploymentManagerImpl.start(DeploymentManagerImpl.java:596)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:97)
at org.wildfly.extension.undertow@7.2.0.GA-redhat-00005//org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:78)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.jboss.threads@2.3.2.Final-redhat-1//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads@2.3.2.Final-redhat-1//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads@2.3.2.Final-redhat-1//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads@2.3.2.Final-redhat-1//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads@2.3.2.Final-redhat-1//org.jboss.threads.JBossthread.run(JBossthread.java:485)
解决方法
这是 JPA 规范要求的预期行为(第 79 页 3.1.1 节)
EntityManager 的方法抛出的运行时异常 LockTimeoutException 以外的接口将导致当前 如果持久性上下文是要标记为回滚的事务 加入了该交易。
要解决此问题,您需要声明要在新事务中执行的方法,使用 REQUIRES_NEW
作为 TransactionAttribute
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。