Jakarta ee 在单个ear中从单例守护程序、MDB和Web控制器与EJB(和EntityManager)交互

Jakarta ee 在单个ear中从单例守护程序、MDB和Web控制器与EJB(和EntityManager)交互,jakarta-ee,singleton,ejb,entitymanager,object-lifetime,Jakarta Ee,Singleton,Ejb,Entitymanager,Object Lifetime,有一个技术栈:javaee(webpere)、JPA、EJB3、JMS(MDB)、JSF 体系结构:JMS消息到达(通过MDB)并注册为持久化实体(使用EntityManager)。有一个具有无限循环的单例类,负责处理这些实体。MDB将向Singleton通知创建的实体。最初,实体存储在单例中的队列中。创建的实体最多可处理几分钟。不能同时处理超过一定数量的实体(单例中的多个并行进程)。Singleton不是EJB,但它使用了EJB服务。有一个类表示给定实体(简单DTO)的执行上下文。执行上下文保

有一个技术栈:javaee(webpere)、JPA、EJB3、JMS(MDB)、JSF

体系结构:JMS消息到达(通过MDB)并注册为持久化实体(使用EntityManager)。有一个具有无限循环的单例类,负责处理这些实体。MDB将向Singleton通知创建的实体。最初,实体存储在单例中的队列中。创建的实体最多可处理几分钟。不能同时处理超过一定数量的实体(单例中的多个并行进程)。Singleton不是EJB,但它使用了EJB服务。有一个类表示给定实体(简单DTO)的执行上下文。执行上下文保存对所需EJB的依赖关系,并在MDB交互步骤上创建,并随通知一条新消息一起传递给Singleton服务(基本上,MDB已注释了这些EJB和EM的注入,并创建了传递这些注入实例的新执行上下文)

问题是:一个实体的处理已经开始,但EntityManager在某个时间点(几秒钟后)开始为搜索请求返回空值,而它不应该返回空值,因为就在一秒钟前,该实体才被更新

看起来架构不太好。我怀疑EM的行为表明,在MDB和Singleton之间的交互完成之后,持久性上下文已经消失了一段时间。 Singleton的生命周期比系统中任何托管bean的生命周期都长。因此,向这样的组件注入EJB实例(和EM实例)似乎根本不是一个解决方案(将注入的EJB实例的引用从MDB传递给Singleton可能是一个最糟糕的决定)

也许EJB和EM应该在每次需要时由使用JNDI的单身汉查找? 在这种情况下,我应该为每个调用锁定EJB吗


您将以何种方式设计系统:如果MDB仅注册消息(作为实体)。实体的处理可能从后者开始。您必须使用一些EJB服务(本地接口)。还有实体管理器。

如果单例使用的实体管理器是事务范围的,那么单例的生存期就无关紧要了。在某种程度上,无状态会话bean在创建后也有一个无限的生存期(它们的作用域基本上是“无”,但它们的实例被合并并继续被重用)

每次singleton中的方法为一个请求提供服务时,都会启动一个新的事务,并将一个新的持久性上下文背负到该事务上,即使在这些请求中实体管理器实例似乎是相同的。这是正常行为,不应“突然”返回空值


如果您的singleton使用了适当的锁,那么可能值得检查一下。如果同时访问实体管理器,则这可能是未定义行为的原因。

EM同时使用,但单个实体在专用线程中按顺序处理(为每个实体创建一个线程,该线程从单例队列中提取)。队列包含实体的ID。一旦线程启动,附加的EM就被用来根据该ID查找实体。在处理序列的第一步中,实体似乎不为null,并且具有正确初始化的成员(引用)。在进一步的步骤中,EM可能不会通过ID返回实体,或者实体的成员可能没有正确填充,例如关系集合可能为空等>EM被同时使用-如果确实如此,则基本上所有赌注都被取消。如果在一个线程中处理单个实体,这并不重要。对于共享EM,行为是未定义的,未定义行为背后的想法就是,如果不知道所有复杂的实现细节(无论如何都不应该依赖这些细节),就无法用逻辑来解释它。因此,解决方案应该相当简单;不要共享实体管理器。谢谢。我认为你是对的,一系列的请求给EM寻找相同的实体,在它们之间有一个短暂的停顿,这会产生不同的结果。如何为不同的线程创建单独的EM实例?使用EntityManagerFactory?最简单的方法可能是将实体管理器注入到一个
@Stateless
bean中,将该bean注入singleton,并将持久性操作委托给该bean。无状态bean自动是线程安全的(对它的每个并发调用都将在封面下路由到不同的实例)。