2012-05-18 43 views
5

Hibernate 3.6.9令人沮喪的問題。 MS SQL Server 2008.請注意異常和奇數列索引引用。休眠異常空值已分配給原始類型設置器的屬性

HQL查詢本身:

Select r from DataStoreReference r join fetch r.container c where r.hash=:hash and r.state=0 

堆棧跟蹤:

2012-05-16 00:01:22,184 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT. 
2012-05-16 00:01:22,186 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT. 
2012-05-16 00:01:22,188 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - Invalid column index 14. 
2012-05-16 00:01:22,190 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT. 
2012-05-16 00:01:22,193 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT. 
2012-05-16 00:01:22,194 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - Invalid column index 14. 
2012-05-16 00:01:22,194 [BackgroundDeletionThread] ERROR com.flipper.utils.ServerErrorHandlerStrategy - reportError: Db :: com.flipper.datastore.workers.BackgroundDeletionThread.executeWork:87 :: EXCEPTION : com.flipper.datastore.exceptions.DBStoreException: Null value was assigned to a property of primitive type setter of com.flipper.datastore.model.DataStoreReference.usage com.flipper.datastore.exceptions.DBStoreException: Null value was assigned to a property of primitive type setter of com.flipper.datastore.model.DataStoreReference.usage 
    at com.flipper.datastore.impl.hib.HibernateDBStore.getAllReferences(HibernateDBStore.java:301) 
    at com.flipper.datastore.workers.BackgroundDeletionThread.processEntry(BackgroundDeletionThread.java:165) 
    at com.flipper.datastore.workers.BackgroundDeletionThread.processSet(BackgroundDeletionThread.java:138) 
    at com.flipper.datastore.workers.BackgroundDeletionThread.executeWork(BackgroundDeletionThread.java:84) 
    at com.flipper.datastore.workers.BackgroundDeletionThread.run(BackgroundDeletionThread.java:60) 
Caused by: org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.flipper.datastore.model.DataStoreReference.usage 
    at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:109) 
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:583) 
    at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:229) 
    at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:3847) 
    at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:152) 
    at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982) 
    at org.hibernate.loader.Loader.doQuery(Loader.java:857) 
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274) 
    at org.hibernate.loader.Loader.doList(Loader.java:2542) 
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276) 
    at org.hibernate.loader.Loader.list(Loader.java:2271) 
    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:459) 
    at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:365) 
    at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196) 
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1268) 
    at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102) 
    at com.flipper.message.dao.DataStoreDao.getAllReferencesByHash(DataStoreDao.java:136) 
    at com.flipper.datastore.impl.hib.HibernateDBStore.getAllReferences(HibernateDBStore.java:298) 
    ... 4 more 
Caused by: java.lang.IllegalArgumentException 
    at sun.reflect.GeneratedMethodAccessor556.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:66) 
    ... 21 more 

現在,我明白這一點從邏輯(和谷歌搜索),如果下面是不正確的

a)DataStoreReference的每個實例都緊接着是System.currentTimeMillis的setUsage)b)該項目在映射中被標記爲非空(見下文) c)導出的表格僅在f_external列中顯示空值。用法列具有完全合理的長數字。

的POJO:

DataStoreReference

private long id; 


private String hash;  
private long date; 
private long sze; 
private long usage; 

private int state; 
private String external; 
private DataStoreContainer container; 

接着通用未經修飾的吸氣/ setter方法。

映射文件:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.flippr.datastore.model"> 
    <class name="DataStoreReference" table="t_dsref"> 
    <id name="id"> 
     <column name="ds_reference_id"/> 
     <generator class="native"/> 
    </id> 
    <property name="hash" not-null="true" column="f_hash" lazy="false" index="idx_hash_dsr" type="string" length="128" /> 
    <property name="state" not-null="true" column="f_state" lazy="false" index="idx_hash_dsr,idx_size_dsr,idx_usage_dsr" type="integer"/> 
    <!-- hibernate hates the name size --> 
    <property name="sze" not-null="true" column="f_size" lazy="false" index="idx_size_dsr" type="long"/> 
    <property name="date" not-null="true" column="f_date" lazy="false" type="long"/>  
    <property name="usage" not-null="true" column="f_usage" lazy="false" index="idx_usage_dsr" type="long"/> 
    <property name="external" not-null="false" column="f_ext" lazy="false" type="string" length="160" /> 

    <many-to-one name="container" class="com.flipper.datastore.model.DataStoreContainer" 
    column="entity_id" foreign-key="fk_ds_container_id_dsr" not-found="ignore" not-null="true"/> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.flipper.datastore.model"> 
  <class name="DataStoreContainer" table="t_dscnt"> 
    <id name="id"> 
      <column name="ds_container_id"/> 
      <generator class="native"/> 
    </id> 
    <property name="containerType" column="f_type" index="idx_containerType_dsc" lazy="false" type="integer"/> 
    <property name="fileCount" column="f_fc" lazy="false" type="long"/> 
    <property name="deletedCount" column="f_dc" lazy="false" type="long"/> 
    <property name="path" column="f_path" length="255" lazy="false"  type="string"/> 
    <set cascade="save-update,delete,delete-orphan,all-delete-orphan" inverse="true" name="documents"> 
      <key column="entity_id" /> 
      <one-to-many class="com.flipper.datastore.model.DataStoreReference"/> 
    </set> 
  </class> 
</hibernate-mapping> 
+0

哦,這裏的實際代碼觸發問題:\t \t \t查詢Q = this.session.createQuery桿菌(Hib) \t \t \t .setString( 「哈希」,散列); \t \t \t @SuppressWarnings( 「未登記」) \t \t \t列表參考= q.list(); // boom – MJB

+0

Hibernate在連接中獲取它,所以我認爲由於索引是14,所以該列可能在'DataStoreContainer'中。 – dasblinkenlight

+0

邏輯,但堆棧中提到的列是使用情況,僅在DataStoreReference中使用。我已經更新了問題以包含其他映射文件 – MJB

回答

2

原來這是一個增強的Hibernate 3.6 MS SQL方言的bug。如果你擴展SQLServer2005或SQLServer2008方言,你將會遇到這個問題。使用較舊的SQLServer方言(這幾乎是Hibernate 3.3x附帶的),你不會。可能與引入分頁支持有關。嘆息

22

的錯誤信息是明確的:在至少一個行的列f_usage具有空值。該空值不能像long那樣放入基本類型,因爲基元類型不能表示空值。

當數據庫中已存在空值時,property子句中的非空屬性不起作用。非空屬性僅用於dmd生成。但是數據庫表t_dsref的f_usage列可能允許空值(在sql中檢查desc t_dsref)。

解決方案:使用你必須處理空條件的值時,例如

if (usage != null) { 
    return usage.longValue(); 
else 
    return -1; 

(您正在使用的getter和setter訪問

private Long usage; 

和:用很久交流hibernate,所以這個codelet不應該在getter中,因爲在數據庫中,null值應該在更新後繼續爲null,但是你可以在第二個getter中使用它,在其他任何地方使用,或者你爲hibernate )

我的一般建議:如果數據庫中的列使用NOT NULL 標記,則只應將基元數據類型用於hibernate屬性。

+1

同意。作爲使用hibernate的最佳實踐,不要使用原始數據類型(將'long'和'int'值更改爲'Long'和'Integer') –

+3

這遠不是最佳實踐。列不爲空時使用基元。可空時使用包裝。 –

+1

不錯的建議,但---正如我所指出的,映射文件的用法爲not-null = true。該數據庫使用內置的模式實用程序從HIBERNaTE生成。數據也被檢查。用法列中沒有NULL值。數據庫是從頭開始使用hibernate創建的,只有hibernate已經填充了它。 – MJB

1

Hibernate需要一些修改來匹配企業發展的現實生活場景。使用對象而不是基元導致比本文中解決的問題更多的問題。

我一直在編碼的Java EE應用程序的企業自2002年以來,以這種使用情況下,最好的解決辦法,考慮到你可能有引用代碼表空值是儘可能更新數據庫許多表。

例如,如果你有一個參考生成代碼表來表示初級,高級等標題的人表和許多條目爲空,更新代碼表有一個未知的參考,然後更新所有空值的表格數據指向該參考。由於大多數Java EE應用程序大而且編碼不佳,您可以嘗試更新這些表的入口點,但很可能這是一團糟,並且可能有各種從cron作業,Web服務等運行的入口點,因此更新DB來捕獲這些空值,並將它們默認爲未知條目並保存你的頭痛。如果你從頭開始構建,這也是一個混亂的休眠,因爲它不是很容易從我可以告訴告訴hibernate是你試圖調用一個基元的setter,它是空的只是讓它0或-1,但然後我再次有不到20小時的休眠體驗。我剛剛閱讀了用戶類型,因此我必須多閱讀一些內容,並瞭解它們的工作原理。在大型Java EE應用程序

的對象是在與目前市場上的編碼器的質量運行時的噩夢。

1

這樣的錯誤在Hibernate中發生,當您使用基本類型某些列但字段在DB空。解決方案:

解決方案一:使用包裝類(Integer for int ...) 解決方法二:定義列的默認值。