如果结果集大小大于1,则Hibernate返回重复值

6

我在PostgreSQL中有一个简单的表叫做“transaction_response”。这个表只有两列:transaction_id和response_id。

我在里面有两行数据。都是相同的transaction_id,但是response_id的值不同。

我创建了以下Java类来存储这些数据:

public class TransactionResponseDAO implements java.io.Serializable {
    private Integer transactionId;
    private Integer responseId;

    public Integer getTransactionId() {
        return transactionId;
    }

    public void setTransactionId(Integer transactionId) {
        this.transactionId = transactionId;
    }

    public Integer getResponseId() {
        return responseId;
    }

    public void setResponseId(Integer responseId) {
        this.responseId = responseId;
    }

    public String toString() {
        return "Transaction Id: " + transactionId + "\nResponse Id: " + responseId;
    }
}

我接下来创建了一个名为“TransactionResponse.hbm.xml”的Hibernate配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.data.TransactionResponseDAO" table="transaction_response">
        <id name="transactionId" column="transaction_id" type="java.lang.Integer">
            <generator class="increment"/>
        </id>

        <property name="responseId" type="java.lang.Integer">
            <column name="responses_id" />
        </property>

    </class>

    <query name="findTransactionResponseByTransactionId">
        <![CDATA[from com.data.TransactionResponseDAO where transaction_id = :transactionId]]>
    </query>

    <query name="findTransactionResponseByBothIds">
        <![CDATA[from com.data.TransactionResponseDAO where transaction_id = :transactionId 
                 and responses_id = :responseId]]>
    </query>
</hibernate-mapping>

我正在测试一个Java类,其中包含以下代码:

Query q = null;
        SessionFactory sFactory = new Configuration().configure("/conf/hibernate.cfg.xml").buildSessionFactory();
        Session session = null;

        try {
            session = sFactory.openSession();
            q = session.getNamedQuery("findTransactionResponseByTransactionId");
            q.setInteger("transactionId", transactionId);
        }catch (Exception e) {
            System.err.println("Error running getStatusTab");
            e.printStackTrace();

            session.close();
            sFactory.close();
        }

        ArrayList<TransactionResponseDAO> results = (ArrayList<TransactionResponseDAO>) q.list();

        session.close();
        sFactory.close();

        System.out.println(">>> Size: " + results.size());

        for (TransactionResponseDAO tr : results) {
            System.out.println(tr);
            System.out.println();
        }

当我运行这段代码时,返回两行结果,正如应该的那样。但是,当打印出这些值时... response_id 对于两行数据都是相同的。因此,出于某种原因似乎没有提取第二个 response_id 值。
有什么原因吗?一如既往,感谢您的帮助!

如果transactionId字段可能包含重复值,则不应该将其设置为映射类的ID。 - dcernahoschi
2个回答

14
问题在于 Hibernate 的缓存机制。当 Hibernate 获取第一行并创建一个对象时,它会根据指定的 id 列(transactionId)对该对象进行缓存。当 Hibernate 获取第二行时,由于这些行具有相同的 id,它认为这是与第一行相同的行,从缓存中获取对象(同一个对象),并将其再次放入结果中。
如果 transactionId 列不唯一,请不要将其映射到 id 标签。

我认为你对直接原因的判断是正确的,但这里真正重要的道德是你的最后一句话! - sharakan
@sharakan 同意。那个transactionId列定义还有另一个问题:如果它被标记为增量,它怎么可能会得到重复的id呢? - DiogoSantana
1
我敢打赌这些行不是由Hibernate插入的,而是手动或通过另一个进程插入的。 - sharakan
@DiogoSantana,我认为你说得对。这不是我的代码,我只是忽略了它... 增量只是试验性地加入其中的。之前它被设置为身份。 - Ascalonian
请将以下与程序设计相关的内容从英语翻译为中文。仅返回翻译后的文本:如果可能,请提供表的主键。 - Abhishyam

0

感谢您的反馈。我的做法是使用复合 ID,这样问题就解决了。再次感谢!

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.data.TransactionResponseDAO" table="transaction_response">
        <composite-id name="primaryKey" class="com.data.TransactionResponsePK">
            <key-property name="transactionId" column="transaction_id" type="java.lang.Integer" />
            <key-property name="responseId" column="responses_id" type="java.lang.Integer" />
        </composite-id>

    </class>

    <query name="findTransactionResponseByTransactionId">
        <![CDATA[from com.data.TransactionResponseDAO tr where tr.primaryKey.transactionId = :transactionId]]>
    </query>

    <query name="findTransactionResponseByBothIds">
        <![CDATA[from com.data.TransactionResponseDAO tr where tr.primaryKey.transactionId = :transactionId 
                 and tr.primaryKey.responseId = :responseId]]>
    </query>
</hibernate-mapping>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接