Pergunta

I'm using Hibernate with the H2 in-memory database. The database tables are automatically created based on the beans information I've provided in the persistence.xml file.

H2 is mapping a field called "created" of type org.joda.time.DateTime to a column of type VARBINARY(255)

When I try to persist my bean with the value created=DateTime.now(), I get the following error:

    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)

Any idea why and what I can do to solve it? Unfortunately I can't change the bean definition, so I have to keep using the joda DateTime.

Thank you!

P.S. This is my 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>

And the table automatically generated by Hibernate / H2:

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

And this is my 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() {
        ...
    }
}
Foi útil?

Solução 2

Here a demonstration (and explanation) of your problem:

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

So a DateTime-object needs 273 bytes when serialized to a byte array. And since the column type does accept byte-arrays, but is configured to only accept as maximum 255 bytes, you get the SQL-exception. There is only one way to solve the problem if you want to keep JodaTime and the byte-array-storage-mechanism: Increase the column size to at least 273 (needs editing of persistence.xml).

EDIT: Is it possible for you to reconsider the storage mechanism? The column type VARBINARY seems not to be the best choice because of its size (and you cannot even apply comparing operators in SQL on this type). Alternatives are VARCHAR (but only in ISO-8601-notation please) or SQL-TIMESTAMP. Watch especially for this Joda-Hibernate-support in order to use Type-annotations and better column types.

Outras dicas

You should use the Joda-Time-Hibernate mapping:

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

You can mapping the CREATED column length on the MYTABLE.groovy domain:

static mapping = {
    CREATED column: "CREATED", sqlType: "VARBINARY", length:273 }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top