我正在编写一个JSF 2.0表单来编辑JPA @Entity对象。我有一个支持bean,它有一个Entity的get方法,它从EntityManager获取。到目前为止一切都很好。
问题是用户正在编辑的Entity对象是否被应用程序的其他部分访问?换句话说,如果其他人调用该记录,他们是否在通过EntityManager将记录合并回数据库之前看到字段更改?或者他们得到一个不同的实例。
这一点很重要的原因是用户可以输入各种不良数据。由支持bean完成的验证阶段不会调用 merge()清除所有错误,但那之前呢?
如果这是一个常见的例子,我该如何避免这个问题?
答案 0 :(得分:3)
问题是用户正在编辑的Entity对象是否被应用程序的其他部分访问?换句话说,如果其他人调用该记录,他们是否在通过EntityManager将记录合并回数据库之前看到字段更改?或者他们得到一个不同的实例。
JSF使用的实体实例将是一个分离的实体实例。它不属于持久化上下文。每个客户端/用户也将收到它自己的分离实体实例。
这一点很重要的原因是用户可以输入各种不良数据。由支持bean完成的验证阶段不会调用merge()所有错误都被清除,但那之前呢?
当您调用EntityManager.merge
以将分离实体的内容与持久性上下文合并时,将发生任何无效数据的合并。如果您从未调用merge
,那么实体的修改内容将永远不会进入持久化上下文。
如果这是一个常见的例子,我该如何避免这个问题?
您可以通过在将实体与持久性上下文合并之前验证实体的状态来避免这种情况。您可以在JSF和JPA中使用bean验证来防止这种情况,尽管您通常只在一个层中执行此操作,以防止进行冗余检查。但是,如果您为bean验证约束指定了验证组以区分表示和持久性约束,那么您应该在两个层中使用bean验证。请记住,一旦bean的内容与持久化上下文成功合并,除了事务回滚或refresh
/ {之外,您无法撤消此更改。 {1}}持久化上下文。
答案 1 :(得分:2)
添加Vineet的正确答案:
您可能有一个由您的支持bean返回的附加实体,例如,如果您使用具有扩展持久性上下文的有状态会话Bean(EJB)。
在这种情况下,您仍然不会冒并发问题的风险,因为持久化上下文的每个实例都返回附加实体的唯一实例(唯一:实例不与其他现有持久性上下文共享)。
此外,如果发生任何类型的验证错误,JSF将不会将更改推送到模型(在这种情况下为附加的JPA实体)。因此,只要您正确设置验证(bean验证或常规JSF验证),就不会有“污染”实体的风险。
此外,请注意,对于附加的案例,您不必调用merge()
,因为这将在上下文关闭时自动发生,因此您将“关闭”有状态bean。
也就是说,常见的情况是Vineet描述了你获得一个独立实体的地方。