p:dataTable 和 JPA 中的乐观锁定
p:dataTable and optimistic locking in JPA
给定 below 使用 PrimeFaces 惰性数据模型的示例性 <p:dataTable>
。关联的JPA实体中被@javax.persistence.Version
标记的行版本字段暂时以只读模式显示在其中一列中。
不用说每个动作都是Ajaxical的。
编辑此 <p:dataTable>
使用 <p:rowEditor/>
作为 follows(table 中的第一行。行版本为 1).
如上通过单击“编辑”列中的勾号更新正在编辑的行时,成功更新后,行版本在数据库中递增到 2,但数据保留的行版本 table仍然是1(见下图)。更新完成后,可以看到数据table的状态为follows.
现在发生的情况是,如果再次尝试同一行(没有通过发送同步 GET 请求刷新页面),那么它将与数据库中当前为 2 的行版本不匹配,因为数据 table 仍然提供版本的旧值,即 1。这将导致 javax.persistence.OptimisticLockException
被抛出,就好像检测到并发更新一样,这显然是不正确的。
可能需要在 <p:dataTable>
(使用 <p:rowEditor/>
)提供的正常 Ajaxical 更新工具中进行彻底更改,以便它与中的乐观锁定策略正确同步地工作JPA.
解决这种情况的正确方法是什么?完全删除 <p:rowEditor/>
将需要对现有应用程序进行巨大的更改,顺便说一下,这是非常不希望的。
虽然 <p:dataTable>
中的 editing/updating 行使用 <p:rowEditor>
,但需要手动将更改同步到 [= 支持的数据模型 (LazyDataModel<T>
) 12=] 更新操作成功完成后。
一种方法是使用 LazyDataModel<T>
中可用的 getWrappedData()
方法,其中 returns 当前由数据 table 支持的数据模型保存的数据以 java.lang.Object
的形式。这是基本用法。
@Named
@ViewScoped
public class Bean extends LazyDataModel<Entity> implements Serializable {
@Inject
private Service service;
private static final long serialVersionUID = 1L;
public Bean() {}
@Override
public List<Fruit> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
setRowCount(service.getRowCount());
// Do something, if necessary.
// Turn the List<SortMeta> into another type like a LinkedHashMap<String, String>.
return service.getList(first, pageSize, multiSortMeta, filters);
}
public void onRowEdit(RowEditEvent event) {
if (event.getObject() instanceof Entity) {
Entity entity = (Entity) event.getObject();
Entity newEntity = service.update(entity); // A new entity from the database.
if (newEntity != null) {
List<Entity> entities = (List<Entity>) getWrappedData();
int index = entities.indexOf(entity);
if (index >= 0) { // The test may be omitted.
entities.set(index, newEntity);
// Just replace the stale/old entity by a newly updated entity in the database.
}
// Add an appropriate FacesMessage to indicate a success.
} else {
// Add an appropriate FacesMessage to indicate a failure.
}
} else {
// Add an appropriate FacesMessage to indicate a failure.
}
}
}
onRowEdit()
方法绑定到 <p:dataTable>
中的 Ajax 侦听器。
<p:ajax event="rowEdit" listener="#{bean.onRowEdit}"/>
我不会接受这个答案,因为可能有更好的方法,但我不知道。欢迎更全面的回答,如有。
给定 below 使用 PrimeFaces 惰性数据模型的示例性 <p:dataTable>
。关联的JPA实体中被@javax.persistence.Version
标记的行版本字段暂时以只读模式显示在其中一列中。
不用说每个动作都是Ajaxical的。
编辑此 <p:dataTable>
使用 <p:rowEditor/>
作为 follows(table 中的第一行。行版本为 1).
如上通过单击“编辑”列中的勾号更新正在编辑的行时,成功更新后,行版本在数据库中递增到 2,但数据保留的行版本 table仍然是1(见下图)。更新完成后,可以看到数据table的状态为follows.
现在发生的情况是,如果再次尝试同一行(没有通过发送同步 GET 请求刷新页面),那么它将与数据库中当前为 2 的行版本不匹配,因为数据 table 仍然提供版本的旧值,即 1。这将导致 javax.persistence.OptimisticLockException
被抛出,就好像检测到并发更新一样,这显然是不正确的。
可能需要在 <p:dataTable>
(使用 <p:rowEditor/>
)提供的正常 Ajaxical 更新工具中进行彻底更改,以便它与中的乐观锁定策略正确同步地工作JPA.
解决这种情况的正确方法是什么?完全删除 <p:rowEditor/>
将需要对现有应用程序进行巨大的更改,顺便说一下,这是非常不希望的。
虽然 <p:dataTable>
中的 editing/updating 行使用 <p:rowEditor>
,但需要手动将更改同步到 [= 支持的数据模型 (LazyDataModel<T>
) 12=] 更新操作成功完成后。
一种方法是使用 LazyDataModel<T>
中可用的 getWrappedData()
方法,其中 returns 当前由数据 table 支持的数据模型保存的数据以 java.lang.Object
的形式。这是基本用法。
@Named
@ViewScoped
public class Bean extends LazyDataModel<Entity> implements Serializable {
@Inject
private Service service;
private static final long serialVersionUID = 1L;
public Bean() {}
@Override
public List<Fruit> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
setRowCount(service.getRowCount());
// Do something, if necessary.
// Turn the List<SortMeta> into another type like a LinkedHashMap<String, String>.
return service.getList(first, pageSize, multiSortMeta, filters);
}
public void onRowEdit(RowEditEvent event) {
if (event.getObject() instanceof Entity) {
Entity entity = (Entity) event.getObject();
Entity newEntity = service.update(entity); // A new entity from the database.
if (newEntity != null) {
List<Entity> entities = (List<Entity>) getWrappedData();
int index = entities.indexOf(entity);
if (index >= 0) { // The test may be omitted.
entities.set(index, newEntity);
// Just replace the stale/old entity by a newly updated entity in the database.
}
// Add an appropriate FacesMessage to indicate a success.
} else {
// Add an appropriate FacesMessage to indicate a failure.
}
} else {
// Add an appropriate FacesMessage to indicate a failure.
}
}
}
onRowEdit()
方法绑定到 <p:dataTable>
中的 Ajax 侦听器。
<p:ajax event="rowEdit" listener="#{bean.onRowEdit}"/>
我不会接受这个答案,因为可能有更好的方法,但我不知道。欢迎更全面的回答,如有。