【问题标题】:EntityManager.persist() works, but EntityManager.merge() does notEntityManager.persist() 有效,但 EntityManager.merge() 无效
【发布时间】:2015-09-02 23:16:18
【问题描述】:

我们正在使用 EclipseLink 2.5.2 和 WildFly 9.0.0。

这是一个每小时调用一定次数的方法(由 EJB 计时器指定)。出于测试目的,我已将其更改为每分钟触发一次,在我的特定配置中,此方法将每分钟调用 10 次,因为要进行 10 次更新:

@Stateless
public class NetCentricDataService {

    @PersistenceContext(unitName = "NetCentricPersistenceUnit")
    private EntityManager em;

    public void insertUpdate(A a, B b, boolean insert) {
        if (insert) {
            em.persist(a);
            em.flush();
            if (b != null) {
                em.persist(b);
                em.flush();
            }
        } else {
            em.merge(a);
            if (b != null) {
                em.merge(b);
            }
            em.flush();
        }
    }
}

当我清除与下面两个实体类关联的表时,if(insert) 块执行,persist 调用工作正常,数据库更新;但是,如果 DB 中存在现有条目,则执行 else 块,merge 调用在没有 Exceptions 的情况下运行,但 DB 不会更新。方法调用完成后,我正在 SQL Developer 中进行检查。

编辑:例如,以下内容不起作用:

A a = dataService.getA(); // gets exisiting A from DB
a.setSubject("My Subject");
B b = dataService.getB(); // gets existing B from DB
b.setFoo(123.45);
insertUpdate(a, b, false);

这里是实体类A:

@Entity
@Table(name = "A")
@SuppressWarnings("unused")
public class A implements Serializable {

    /**
     * Method called by container before DB insert.
     */
    @PrePersist
    public void beforeInsert() {
        if (objectType == null) {
            objectType = ObjectTypeEnum.UNKNOWN;
        }
    }

    @Id
    @Column(name = "MY_UID")
    private String myUid;

    @Column(name = "MY_NUMBER")
    private int myNumber;

    @Column(name = "SUBJECT")
    private String subject;

    @Enumerated(EnumType.ORDINAL)
    @Column(name = "OBJECT_TYPE")
    private ObjectTypeEnum objectType;

    // other columns, getters, setters, equals, etc.

}

这里是实体类 B:

@Entity
@Table(name = "B")
@SuppressWarnings("unused")
public class B implements Serializable {

    @Id
    @Column(name = "MY_UID", nullable = false)
    private String myUid;

    @Column(name = "FOO")
    private double foo;

    @Column(name = "BAR")
    private double bar;
}

注意:B 中的 MY_UID 是 A 中 MY_UID 的外键。

注意:我尝试更新的任何列都没有 updatable=false 属性。

如果还有其他文件/方法/等,请告诉我。我可以提供,或者如果我可以提供更多信息。还值得注意的是,我不维护我发布的任何代码,但我最近一直在使用它。我问了维护者,他说他不确定为什么会发生这种情况。提前感谢您的帮助!

编辑 - 这是来自standalone-full.xml 的数据源配置:

<subsystem xmlns="urn:jboss:domain:datasources:3.0">
        <datasources>
            <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
                <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
                <driver>h2</driver>
                <security>
                    <user-name>sa</user-name>
                    <password>****</password>
                </security>
            </datasource>
            <datasource jta="true" jndi-name="java:jboss/datasources/SFDS" pool-name="SFDS" enabled="true" use-java-context="true" use-ccm="true">
                <connection-url>jdbc:oracle:thin:@DB:1521:ORACLE_SID</connection-url>
                <driver>ojdbc6</driver>
                <new-connection-sql>select 1 from dual</new-connection-sql>
                <pool>
                    <min-pool-size>10</min-pool-size>
                    <max-pool-size>100</max-pool-size>
                    <prefill>false</prefill>
                    <use-strict-min>false</use-strict-min>
                    <flush-strategy>FailingConnectionOnly</flush-strategy>
                </pool>
                <security>
                    <user-name>wildfly_user</user-name>
                    <password>****</password>
                </security>
                <validation>
                    <check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
                    <use-fast-fail>true</use-fast-fail>
                </validation>
            </datasource>
            <drivers>
                <driver name="h2" module="com.h2database.h2">
                    <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                </driver>
                <driver name="ojdbc6" module="com.oracle.jdbc">
                    <xa-datasource-class>oracle.jdbc.OracleDriver</xa-datasource-class>
                </driver>
            </drivers>
        </datasources>
    </subsystem>

【问题讨论】:

  • 在您的示例中,ID 是如何设置的?您是否尝试使用合并插入具有空 ID 的 A 和 B 实例?如果 B 的 ID 是 A 的外键,如何设置?
  • 抱歉,我在 merge() 之前编辑了我的示例。它从已经设置了 MY_UID 字段的数据库中获取现有的 A 和 B。例如,假设表是空的。对程序的第一次调用将创建一个新的 A 和 B,然后调用 a.setMyUid(UUID.randomUUID().toString());b.setMyUid(a.getMyUid());,以及传入的任何更新。现在它们已设置。然后下一个调用将获取现有的 A 和 B,设置一些新字段,然后尝试合并。
  • 我还想看看 WildFly 中的数据源配置。如果你使用容器的连接池。数据源使用什么数据库和 jdbc 驱动程序。这取决于你如何运行 WildFly,通常standalone.xml 是感兴趣的文件
  • 我已经在问题中包含了数据源配置。查看我的编辑。
  • getA 是什么样的?我能看到的唯一会导致这种情况的是,如果您正在更改共享缓存中的对象,以便在合并更改的对象时,Eclipselink 不会看到有更改。确保您对 A 和 B 的查询没有尝试获取只读实例或可能导致它从共享缓存返回只读实例的优化。尝试在合并之前显式调用 em.find 并将查找返回的内容与您的实体中的内容进行比较。

标签: java merge persistence eclipselink entitymanager


【解决方案1】:

问题似乎在于,在尝试调用 merge 之前,我们调用了带有只读提示的 SELECT 查询。删除此提示允许合并成功显示在数据库中。感谢克里斯的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-08
    • 2012-05-08
    • 2017-03-15
    • 2014-10-30
    • 2011-03-08
    • 2013-11-27
    • 2010-11-29
    • 2017-12-13
    相关资源
    最近更新 更多