具有扩展持久性上下文的有状态EJB,用于处理用户会话

时间:2011-06-14 18:22:55

标签: java jsf jpa ejb cdi

我正在使用CDI会话范围的bean来保存用户相关信息(他的用户实体bean,凭证等)。每次用户更改其信息(如电子邮件,密码等)时,我都有一个保存方法。 但是,我可以使用具有扩展持久性上下文的有状态会话bean来执行此操作。如果我这样做,他的用户实体将在他的会话期间被管理,并且他的电子邮件等的更改将被同步而不重新创建持久性上下文等。 这是一个好主意吗?我应该有一个扩展的持久化上下文打开这么久吗?这也锁定了外部bean对用户的更改吗?如果我有管理员尝试对此用户进行更改(可能会发生),该怎么办?

2 个答案:

答案 0 :(得分:5)

您需要注意一些副作用。

首先,用于保存此用户实体的扩展持久性上下文不应该用于其他许多内容,因为它会自动缓存所有被触摸的内容(L1缓存)。

如果您需要在处理其他持久性上下文的其他操作中使用此连续附加的用户实体,则需要获取新的实例,而不是在会话范围中使用该实例。

锁定事情不会自动发生。通常,不同的持久性上下文也可以修改同一个实体。通常,进行任何写入的最后一个将“赢”。如果要防止这种情况,可以利用JPA中的常规锁定操作。对于这种情况,乐观锁可能是最合适的。

我很好奇,但这在实践中会有多好。这肯定是一个新颖的想法。通过阅读许多博客文章,文章,书籍和与许多开发人员的讨论,我感觉扩展的持久化上下文是相当鲜为人知的事情,并没有为它创建那么多的最佳实践。

有状态会话bean现在可以通过CDI进行范围化(因此在例如HTTP会话被破坏时自动销毁)这一事实使得整个概念更加可行。但CDI也相对较新,很多人仍然需要发现如何最好地使用它。

答案 1 :(得分:5)

我在各种Java EE 6项目中使用扩展持久化上下文,这就是场景:

  • facade ”(sfsb),注入服务
  • 服务”注入EM
  • dbproducer ”将EM生成到立面的会话范围
  • 默认情况下,立面禁用所有交易(例如loadEntity()没有交易)
  • 某些外观方法明确启用交易(例如saveEntity()有转化)

会发生什么:

  • 一个实体被加载并在整个会话期间保持管理(完全由持久化上下文缓存,在没有事务的情况下 - 不会刷新)。
  • 如果(并且仅为了示例)保存了实体,则将显式打开事务,并且如果事务成功,则持久性上下文将刷新到db中。
  • 如果确实发生了任何其他编辑(例如由管理员),则会抛出OptimisticLockingException并由应用程序处理

这就像一个魅力,也感觉非常优雅: - )

一句警告 - 由于EM不可序列化 - * 如果* 您正在群集中工作,您将被迫使用粘性会话策略,因为这些EJB不能从一台服务器转移到另一台服务器。

您可能还想考虑让EM加入现有事务的某种方式(如果每个请求有多个服务调用,这很容易发生)。如果您使用非Seam 3堆栈,则代理EM是一个选项,如果您使用的是Seam 3,请使用@Unwraps(Solder)而不是@Produces并检查是否有要加入的事务