在JSF(Primefaces)应用程序中,我有以下实体:
@Entity
@Table(name = "shop_tree")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "itemType", discriminatorType = DiscriminatorType.STRING)
@NamedQuery(name = "selectSorted", query = "SELECT t FROM ShopTree t ORDER BY t.parentId ASC, t.position ASC")
public abstract class ShopTree implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
private Long parentId;
@NotNull
private Integer position = 0;
@NotNull
private String name;
private String seoLinkName;
@Enumerated(EnumType.STRING)
@Column(name = "itemType", insertable = false, updatable = false)
@NotNull
private TreeItemType itemType = TreeItemType.SPACER;
private boolean released;
private int importError;
private boolean seoRelevant;
@Version
@Column(name = "version", nullable = false)
private long version = 0l;
而这两个方法在相应的Facade类(一个@Stateless bean)中:
public T merge(T entity) throws ConcurrentUpdateException {
try {
return getEntityManager().merge(entity);
} catch (OptimisticLockException ex) {
log.warn("OptimisticLocking Exception: ex.getEntity() {} - entity {}", ex.getEntity().getClass().getName(), entity);
throw new ConcurrentUpdateException(entity);
}
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
从这个基类继承了大约6种特殊类型,所有这些类型只包含1或2个基本属性,如附加的int,long或string - 真的没什么特别的 .
例:
@Entity
@DiscriminatorValue(TreeItemType.Values.FREE_LINK)
public class Freelink extends ShopTree {
private String freeLink;
public Freelink() {
super();
this.setItemType(TreeItemType.FREE_LINK);
}
// Getter /Setter
}
由于实体形成了一个有点复杂的树结构,我将它们读入内存(通过命名查询)并将它们保存在会话中 . 现在,当一个会话中的用户删除一个项目而另一个用户编辑其中一个已删除的实体时,该实体将再次存储在数据库中 - 没有任何例外 . 它获得了一个新的id,就像我使用persist而不是merge一样 .
怎么可能?不应该有例外吗?
所有删除和合并都是通过上述方法完成的,绝对没有例外 .
有什么办法可以阻止jpa再次将删除的实体保存到数据库中 . 我希望JPA知道我刚尝试的实体
我在用
-
wildfly 8.2.0-final(这意味着hibernate 4.3.1我认为和
-
java 8
-
Java ee 7 api
-
JSF 2.2
1 回答
如果你使用没有任何存在的
merge
方法检查你假设你是唯一一个持有数据的那一刻,合并会进行会话检查,但实体不在会话中,因为它是一个表单帖子,所以它尝试从数据库中获取,但已被删除(删除已提交),它将对象标记为新(然后提交创建插入语句) .如果按照设计,您知道其他用户可以修改或删除相同的实体,则需要在合并之前执行手动存在检查,或使用锁定行为来阻止对相同对象的并发编辑 .