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

arg*_*g20 3 java jsf ejb jpa cdi

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

Arj*_*jms 5

您需要注意一些副作用.

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

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

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

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

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


jan*_*oth 5

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

  • 一个" 门面 "(sfsb),注入服务
  • " 服务 "注入EM
  • " dbproducer "将EM生成到立面的对话范围中
  • 外观默认禁用所有事务(例如loadEntity(),没有事务)
  • 某些Facade方法明确启用事务(例如,saveEntity()有一个转换)

会发生什么:

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

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

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

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