2014-04-04 47 views
3

我在H內存數據庫中使用Hibernate。 數據庫表是根據我在persistence.xml文件中提供的bean信息自動創建的。在H2數據庫和joda中使用Hibernate DateTime

H2被映射了一個名爲「創造」 型org.joda.time.DateTime 字段類型的列VARBINARY(255)

當我嘗試用價值堅持我的豆created=DateTime.now(),我得到以下錯誤:

Caused by: org.h2.jdbc.JdbcSQLException: Value too long for column "CREATED BINARY(255)": "X'aced0005737200166f72672e6a6f64612e74696d652e4461746554696d65b83c78646a5bddf90200007872001f6f72672e6a6f64612e74696d652e62617365... (273)"; 
    SQL statement: 
    insert into mytable (id, created) values (null, ?) [22001-168] 
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329) 

任何想法,爲什麼和我能做些什麼來解決呢? 不幸的是我不能改變bean的定義,所以我必須繼續使用joda DateTime。

謝謝!

P.S.這是我的persistence.xml

<persistence-unit name="my-test" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 

    <class>com.model.MyTable</class> 

    <exclude-unlisted-classes>true</exclude-unlisted-classes> 
    <shared-cache-mode>ALL</shared-cache-mode> 

    <properties> 
     <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" /> 
     <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/c:\UnitTest;INIT=CREATE SCHEMA IF NOT EXISTS UnitTest" /> 
     <property name="javax.persistence.jdbc.user" value="SA" /> 
     <property name="javax.persistence.jdbc.password" value="" /> 
     <property name="hibernate.hbm2ddl.auto" value="create-drop" /> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> 
     <property name="hibernate.show_sql" value = "true" /> 

     <property name="hibernate.cache.use_query_cache" value="true" /> 
     <property name="hibernate.max_fetch_depth" value="4" /> 
     <property name="hibernate.cache.use_second_level_cache" value="true" /> 
     <property name="hibernate.cache.use_query_cache" value="true" /> 
     <property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory" /> 
    </properties> 

</persistence-unit> 

,而表由Hibernate/H2自動生成:

MYTABLE 
    ID BIGINT(19) NOT NULL 
    CREATED VARBINARY(255) 

,這是我的bean:

@Entity 
@Table(name = "MyTable") 
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) 
public class MyTable implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Long id; 

    public Long getId() { 
     return id; 
    } 

    @SuppressWarnings("unused") 
    private void setId(Long id) { 
     this.id = id; 
    } 

    @Column(name = "created") 
    private DateTime created; 

    public DateTime getCreated() { 
     return created; 
    } 

    @SuppressWarnings("unused") 
    private void setCreated(DateTime created) { 
     this.created = created; 
    } 

    public MyTable() { 
    } 

    public MyTable(DateTime created) { 
     this.created = created; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     ... 
    } 

    @Override 
    public int hashCode() { 
     ... 
    } 
} 
+1

你能告訴我們你的映射表? –

+0

嗨,Jon,你想看看bean,生成的H2 SQL表或persistence.xml嗎? – Gep

+0

persistence.xml文件 - 只是相關的部分。 (如果你可以創建一個簡短但完整的例子來證明這個問題,那將是理想的。) –

回答

2

這裏演示(和解釋)您的問題:

ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
ObjectOutputStream oos = new ObjectOutputStream(bos); 
oos.writeObject(new DateTime()); 
oos.close(); 
System.out.println("Serialized size: " + bos.toByteArray().length); // output: 273 

因此,一個DateTime對象在序列化爲字節數組時需要273個字節。由於列類型確實接受字節數組,但被配置爲只接受最多255個字節,所以會得到SQL異常。如果要保留JodaTime和字節數組存儲機制,只有一種方法可以解決問題:將列大小增加到至少273(需要編輯persistence.xml)。

編輯:你有可能重新考慮存儲機制嗎?列類型VARBINARY似乎並不是最好的選擇,因爲它的大小(並且甚至無法將SQL中的比較運算符應用於此類型)。替代方法是VARCHAR(但僅限於ISO-8601-notation)或SQL-TIMESTAMP。特別注意這個Joda-Hibernate-support以便使用Type-annotations和更好的列類型。

+0

這個。如果您不能編輯bean定義,請更改數據庫架構。總之,TIMESTAMP比VARBINARY更適合存儲時間戳。哦,除非你使用Java 8,否則你會很高興你使用Joda-Time。 :) –

+1

只需注意:JDK-GregorianCalendar甚至需要災難性的2385字節!所以JodaTime好多了。JSR-310(和我的庫)在序列化行爲方面進一步改進(大約100字節 - 實際上無法測試)。 –

+0

謝謝梅諾,這是一個很好的解釋。存儲機制(即VARBINARY)由Hibernate/H2自動生成。我想我可以手動指定數據庫表,但我有大約100個......所以我希望有一種解決方法或一種方法來告訴Hibernate以不同的方式轉換joda DateTime。 – Gep

0

可以映射在MYTABLE.groovy域創建列長度:

static mapping = { 
    CREATED column: "CREATED", sqlType: "VARBINARY", length:273 } 
2

您應該使用喬達 - 時間 - Hibernate映射:

@Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")

相關問題