2013-03-27 117 views
3

我在PostgreSQL中有一个名为“transaction_response”的简单表。在这个表中,只有两列:transaction_id和response_id。如果结果大小大于1,Hibernate会返回重复值

我在那里的数据有两行。两者具有相同的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(); 
     } 

当我运行这段代码,它retur返回两行,正如它应该的那样。但是,在打印出值时,两行的response_id都是相同的。因此,出于某种原因,它似乎没有拉入第二个response_id值。

这是什么原因?一如既往,我感谢帮助!

+0

如果可能包含重复值,则不应将transactionId字段设置为映射类的ID。 – dcernahoschi 2013-03-27 17:54:48

回答

8

问题是hibernate的缓存机制。当hibernate获取第一行并创建一个对象时,它通过指定的id列(transactionId)来缓存该对象。当hibernate获取第二行时,它认为它与第一行是同一行,因为这些行具有相同的id,从缓存中获取对象(同一对象)并将其放在结果上。

如果colum transactionId不唯一,请不要将它与id标签进行映射。

+0

我认为你是对的最接近的原因,但真正重要的道德在这里是你的最后一行! – sharakan 2013-03-27 17:56:14

+0

@sharakan同意。该transactionId列定义的另一个问题:如果标记为增量,它如何获得重复ID? – DiogoSantana 2013-03-27 17:57:58

+1

我敢打赌,这些行不是由Hibernate插入的,而是由人工或其他进程插入的。 – sharakan 2013-03-27 17:58:54

0

谢谢您的反馈。我所做的是使用composite_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>