java - 使用集合更新实体的 JPA 最佳实践

标签 java jpa collections entity

我在 Glassfish 容器中使用 JPA。我有以下模型(不完整)

@Entity
public class Node {
    @Id
    private String serial;
    @Version
    @Column(updatable=false)
    protected Integer version;
    private String name;
    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    private Set<LUN> luns = new HashSet<LUN>();

@Entity
public class LUN {
    @Id
    private String wwid;
    @Version
    @Column(updatable=false)
    protected Integer version;
    private String vendor;
    private String model;
    private Long capacity;
    @ManyToMany(mappedBy = "luns")
    private Set<Node> nodes = new HashSet<Node>();

此信息将每天更新。现在我的问题是,执行此操作的最佳实践是什么。

我的第一个方法是,我每天在客户端上生成新的节点对象(带有 LUN),并通过服务将其合并到数据库(我想让 JPA 来做这项工作)。

现在我做了一些没有 LUN 的测试。我在无状态 EJB 中有以下服务:

public void updateNode(Node node) {
    if (!nodeInDB(node)) {
        LOGGER.log(Level.INFO, "persisting node {0} the first time", node.toString());
        em.persist(node);
    } else {
        LOGGER.log(Level.INFO, "merging node {0}", node.toString());
        node = em.merge(node);
    }
}

测试:

@Test
public void addTest() throws Exception {
    Node node = new Node();
    node.setName("hostname");
    node.setSerial("serial");
    nodeManager.updateNode(node);
    nodeManager.updateNode(node);
    node.setName("newhostname");
    nodeManager.updateNode(node);
}

这无需 @Version 字段即可工作。使用 @Version 字段,我得到一个 OptimisticLockException。

这是错误的做法吗?我是否必须始终执行 em.find(...),然后通过 getter 和 setter 修改托管实体?

感谢任何帮助。

BR雷内

最佳答案

@version 注解用于启用乐观锁定。

当您使用乐观锁定时,每次成功写入表都会增加一个版本计数器,每次持久化实体时都会读取并比较该计数器。如果您第一次发现实体时读取的版本与写入时表中的版本不匹配,则会引发异常。

您的程序在仅读取一次版本列后多次更新该表。因此,在第二次调用 persist() 或 merge() 时,版本号不匹配,查询失败。这是使用乐观锁定时的预期行为:您试图覆盖自第一次读取以来已更改的行。

回答你的最后一个问题:每次写入数据库后,你都需要读取更改后的@version信息。您可以通过调用 em.refresh() 来完成此操作。

但是,您应该考虑重新考虑您的策略:乐观锁最好在事务上使用,以确保用户执行更改时数据的一致性。这些通常读取数据,将其显示给用户,等待更改,然后在用户完成任务后保留数据。在这种情况下,您实际上并不希望也不需要多次写入相同的数据行,因为事务可能会由于每一个写入调用上的乐观锁定而失败 - 这会使事情变得复杂而不是让它们变得更简单。

关于java - 使用集合更新实体的 JPA 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4616494/

相关文章:

java - 更新调度程序上的 Activity 集合

c# - 将 NHibernate 集合延迟加载到 ViewModel 中?

java - 按位置或索引从 Android 中的 HashMap 获取键

java - Hibernate DDL 与 validator 注释

spring - hibernate 不支持的功能

.net - 寻找一种将大量对象加载到 .NET 中的 IDictionary 的技术

java - 需要正则表达式帮助

java - Android Array Adapter 选择了错误的 ID

java - MapSqlParameterSource 无法与存储过程的 NamedParameterJdbcTemplate 正确映射

java - 是否可以禁用每个特定查询的 jpa 提示?