【问题标题】:Question about multi-threading and EntityManager关于多线程和EntityManager的问题
【发布时间】:2011-08-30 17:30:49
【问题描述】:

我一直在使用 JPA 2.0 实现 EclipseLink 2.2.0 开发我的网络应用程序。我终于开始运行多线程代码,但遇到了这个异常:

java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager.

在我的应用程序中具有所有 javax.persistence 调用的对象被定义为应用程序范围,如下所示:

@Model
@ApplicationScoped
public class LocationControl implements Serializable {

    @PersistenceContext private EntityManager   em;
    @Resource           private UserTransaction utx;

    // etc

当然,所有想要访问数据库的托管 bean(通常是 RequestScoped 或 ConversationScoped)都是这样做的:

@Inject private LocationControl lc;

所以我的问题是:我是否通过使用 @ApplicationScoped DAO 获得了该异常?我原以为这样会更有效,因为如果容器没有范围,容器就不必在每个请求上不断地重新创建这个对象,并且 DAO 没有自己的状态。但是,如果 EntityManager 和 UserTransaction 对象必须是每个用户的单独实例,那么这将是一个问题。

或者,我可以在 DAO 方法上使用 syncrhonized,但我认为这会导致容器中的线程锁定 (GlassFish)。

任何建议表示赞赏。

【问题讨论】:

  • 我不做 CDI,但 LocationControl 通常应该是 @Stateless EJB 并且将由 @EJB 注入。我不知道@Model 代表什么,但这在商务服务类上是错误的。

标签: jsf-2 glassfish jpa-2.0 glassfish-3 cdi


【解决方案1】:

@Model 注释最初是为了注释请求范围的 bean 而创建的,它是这样定义的:

@Named

@RequestScoped

@Stereotype

@Target({TYPE, METHOD, FIELD})

@Retention(RUNTIME)

public @interface Model {}

您当然可以用另一个注释覆盖“@RequestScoped”,但“@ApplicationScoped”不是一个好的选择,因为应用程序中的每个人都会修改同一个注入的 EntityManager 的状态。我认为在大多数情况下最好将其保留为 @RequestScoped,有时,例如对于登录/注销数据 bean,“@SessionScoped”可能是一个选项,但我看不到“@ApplicationScoped”dao 的场景。

如果您根本不想使用 @Model 并且使用完整的 Java EE 容器,那么正如 BalusC 所说,无状态 EJB 对 Dao 来说也是一个不错的选择。

【讨论】:

  • 我认为我们在这里对“@Model”的使用偏离了方向。实际上它是“@Named”的扩展,我正在将我的代码转换为使用“@Named”。但真正的问题是我是否可以使用单个 DAO 实例及其对单个 EntityManager 和 UserTransaction 的引用以及多个线程。
  • 即使你使用 '@Named' 而不是 '@Model' 并且仍然使用 '@ApplicationScope' 你会让你的实体管理器全球化,在我看来它不应该。
  • 好的,我想我将不得不这样做。感谢您的意见。
猜你喜欢
  • 2019-04-12
  • 1970-01-01
  • 2016-09-11
  • 1970-01-01
  • 2019-03-08
  • 2011-01-29
  • 1970-01-01
  • 2010-09-15
  • 2011-04-22
相关资源
最近更新 更多