【问题标题】:Entity data reset when a lazy LOB is changed更改惰性 LOB 时重置实体数据
【发布时间】:2015-07-27 13:06:38
【问题描述】:

我正在使用 Glassfish 4 (JavaEE7) 和 EclipseLink (JPA2.1) 开展一个大型项目。 当我修改 LOB 字段的值时,这会重置实体的所有先前值。

例如,我有以下实体:

@Entity
@Table(name="person")
public class Person implements Serializable {
    @Id
    @Column(name = "ID")
    private Integer id;
    @Column(name = "LASTNAME")
    private String lastname;
    @Column(name = "FIRSTNAME")
    private String firstname;
    @Column(name = "VERSION")
    private Integer version;
    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(name = "REMARKS")
    private String remarks;

    /* getter & setters */
}

我使用以下代码更新我的实体:

@Singleton
@TransactionManagement(TransactionManagementType.BEAN)
@Startup
public class ModifierBean implements ModifierBeanLocal {

    @Resource
    private UserTransaction userTransaction;

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public String modify(Integer id, String lastname, String firstname, String remarks) {
        try {
            StringBuilder result = new StringBuilder(256);

            userTransaction.begin();
            Query query = entityManager.createQuery("SELECT p FROM Person p WHERE p.id = ?1");
            query.setParameter(1, id);

            Person p = (Person)query.getSingleResult();
            result.append("State 0: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            p.setFirstname(firstname);
            p.setLastname(lastname);
            p.setVersion(p.getVersion()+1);
            result.append("State 1: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            p.setRemarks(remarks); //  <= reset the other fields
            result.append("State 2: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            userTransaction.commit();
            return result.toString();
        } catch(Exception e) {
            //...
        }
    }
}

当我运行以下代码时,这是我从 Bean 获得的输出:

State 0: lastname=Smith, firstname=John, version=0
State 1: lastname=John2, firstname=Smith2, version=1
State 2: lastname=Smith, firstname=John, version=0

正如我们所看到的,当加载 LOB 时,then 实体的值会被重置,这对我的目的来说非常烦人。 有一些技巧可以防止这种情况发生,例如我测试了以下选项:

  • 在修改 LOB 字段之前调用 entityManager.flush()
  • 在进行第一次修改之前调用 p.getRemarks()

我还注意到,如果 LOB 字段没有更改,那么值就会正确提交。 我知道 LAZY 值是按需加载的,但我不明白为什么它会重置所有其他值。

这是错误还是标准行为?有没有办法让它按预期工作(不重置值)?

【问题讨论】:

标签: eclipselink java-ee-7 jpa-2.1 glassfish-4.1


【解决方案1】:

我刚刚发现这个确切的错误已在 EclipseLink 中打开(自 v2.1.3 以来已经存在):https://bugs.eclipse.org/bugs/show_bug.cgi?id=371743

【讨论】:

    【解决方案2】:

    这取决于您的持久性单元属性及其与事务的关联。不过我相信,由于您没有明确地将 EntityManager 加入事务,Em 的行为就好像它在事务之外,导致以下行为适用:

    “外部事务整个对象(包括获取组成员)在共享缓存中刷新。” http://wiki.eclipse.org/EclipseLink/Development/2.1/AdvancedJPA_Queries/FetchGroup

    尝试调用 entityManager.joinTransaction();开始交易后看看这是否有帮助。 EclipseLink

    【讨论】:

    • 您好,感谢您的回复。我试图调用 entityManager.joinTransaction(),但问题仍然存在。由于 EntityManager 是由应用程序容器创建的,它知道 JTA 事务,因此不需要调用 joinTransaction。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    相关资源
    最近更新 更多