JPA:“列太长的数据”不会改变

时间:2012-09-13 06:45:21

标签: hibernate jpa longtext

我的一个实体Machinery有一个名为String的{​​{1}}属性。 JPA 2-Hibernate为我生成了模式,在我的例子中,RDBMS是一个MySQL。

notes被创建为notes列,这是正确的。

用户开始创建记录并且所有工作都完美无缺,但是有些用户会收到臭名昭着的VARCHAR(255)错误。

该字段没有足够的空间容纳用户的机器记录!好的,没问题。让我们改变架构!

所以,我打开我的实体类并将我的属性更改为:

Data too long for column "notes"

顺便说一句,我的@Column(length=1000000) @Lob private String notes; 声明:

persistence.xml

重启应用程序后,我很高兴Hibernate正在将<property name="hibernate.hbm2ddl.auto" value="update" /> 列更改为notes(这对我来说已经足够了)。

所以我首先尝试使用我的应用程序创建一个新的“久负盛名”记录,但我仍然是错误“数据太长”,尽管现在是LONGTEXT

然后,我尝试从MySQL命令行执行原始LONGTEXT并且它可以工作!我可以在该字段中插入长音符!

最后,我INSERT我的本地/暂存数据库架构,并将DROP中的hibernate.hbm2ddl.auto更改为persistence.xml,然后就可以了。

JPA是否仍然认为它是create?它是否有某种缓存或存储模式信息的某个位置?

显然,我不能放弃我的生产数据库。那么,我该怎么做才能重置或更改列类型?

我正在使用JBossAS7 JPA 2-Hibernate。

10 个答案:

答案 0 :(得分:20)

权威的Hibernate书“Java持久性与Hibernate”提到了 hibernate.hbm2ddl.auto 更新值(粗体是我的)

  

此配置属性update的附加选项可以是   在开发过程中很有用:它启用了内置的SchemaUpdate工具,   这可以使架构演变更容易。如果启用,Hibernate会读取   启动时的JDBC数据库元数据并创建新表和   通过比较旧模式和当前映射来进行约束   元数据。 请注意,此功能取决于质量   JDBC驱动程序提供的元数据,其中有许多驱动程序   缺乏。实际上,这个功能因此不那么令人兴奋   听起来很有用。

Hibernate文档也建议使用相同的here

  

SchemaUpdate工具将使用更新现有架构   “增量”变化。 SchemaUpdate依赖于JDBC元数据   API,因此不适用于所有JDBC驱动程序。

我试图复制你的用例,并且发现我也遇到了这个问题,这令人惊讶。

我有一个像这样的用户实体

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table( name = "usr" )

public class User {
  @Id
  @GeneratedValue
  private Long id;

  @Column( length = 40, unique = true )
  private String name;

  @Lob
  @Column( length = 100000 )
  private String text;

  public long getId() {
    return id;
  }

  public void setName( String name ) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public String getText() {
    return text;
  }

  public void setText( String text ) {
    this.text = text;
  }

}

和我的持久性xml就像这样

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
   <persistence-unit name="jpatest" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="root"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpadatabase"/>
            <property name="hibernate.show-sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

如果我更改hibernate.hbm2ddl.auto的值以创建实体的text属性并将其更改为

.....

  @Column( length = 255 )
  private String text;
......

架构生成器在启动时生成以下sql

DEBUG SchemaExport:415 - drop table if exists usr
DEBUG SchemaExport:415 - create table usr (id bigint not null auto_increment, name varchar(40) unique, text varchar(255), primary key (id)) ENGINE=InnoDB
INFO SchemaExport:281 - schema export complete

现在再次更改实体中的属性

.....
@Lob
@Column( length = 100000 )
private String text;
.......

现在生成正确的sql

DEBUG SchemaExport:415 - drop table if exists usr
DEBUG SchemaExport:415 - create table usr (id bigint not null auto_increment, name varchar(40) unique, text longtext, primary key (id)) ENGINE=InnoDB
INFO SchemaExport:281 - schema export complete

到目前为止一切顺利。

现在,如果我将值hibernate.hbm2ddl.auto更改为更新并以相同顺序重复实体中的上述更改,则尽管我已从varchar(255)更新了text列,但仍未生成更新列sql到LONGTEXT

 INFO TableMetadata:65 - table found: jpadatabase.usr
 INFO TableMetadata:66 - columns: [id, text, name]
 INFO TableMetadata:68 - foreign keys: []
 INFO TableMetadata:69 - indexes: [name, primary]
 DEBUG DefaultIdentifierGeneratorFactory:90 - Setting dialect  [org.hibernate.dialect.MySQL5InnoDBDialect]
 INFO SchemaUpdate:217 - schema update complete

但是,如果我使用update和而不是修改属性,我会添加另一个属性位置,然后再次生成正确的sql

DEBUG SchemaUpdate:203 - alter table usr add column location varchar(255)
INFO SchemaUpdate:217 - schema update complete

因此,本质上,create(首先删除表然后重新创建)正常工作,但是如果属性元数据中有修改则更新不会。

对我来说,看起来驱动程序支持增量更新的问题在这里发挥作用。 同样直观如果我考虑到这一点,那么支持更新列的数据类型是没有意义的。如果修改后的列数据类型是早期数据类型的缩小版本,现有数据会发生什么。

答案 1 :(得分:7)

我刚刚遇到这个问题,在阅读本文后我发现了答案,如果你考虑它是非常合乎逻辑的,与审计的envers表有关。

如何重现

  • 您正在使用hibernate envers
  • 您可以在添加注释@Lob的代码中更改列的类型。

原因

Hibernate只更新原始表,而不是经过审计的表,这就是hibernate所做的:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

症状

对于列&#39; x&#39;&#34;

,臭名昭着的#34;数据太长了会引发MysqlDataTruncation异常。

解决方案

手动更新审计表的类型。 例如:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

这非常棘手,因为异常只说明了列的名称而不是表的名称!!这就是为什么删除和重新创建模式也有效,导致审计表被重新生成。

答案 2 :(得分:4)

我有同样的问题INSTER语句完全直接在数据库上工作,但是通过Hibernate完成它并不起作用并产生数据截断:数据太长了列。当hbm2ddl更改为create-drop时,一切正常。

但我真正的问题是由于我在审计功能中使用Hibernate构建使用Audit表。主表已正确更新为增加的大小但未更新审计表,因此写入Audit表的所有更改都会导致此数据截断错误。只需手动将Audit表中的列更新为正确的大小,一切正常。

答案 3 :(得分:4)

我也有相同的情况,下面的情况对我来说很顺利

@Column(name="your_column_name",columnDefinition="LONGTEXT")
private String notes;

我知道很久以前有人问过这个问题,但对某人还是有帮助的。 :)

答案 4 :(得分:3)

什么!我结束了: - 数据库备份 - hbm2ddl =&gt; CREATE-DROP - hbm2ddl =&gt; UPDATE - 数据库恢复

疯狂! :(

答案 5 :(得分:3)

我认为这解决了这个问题 @Column(columnDefinition="LONGVARCHAR")

答案 6 :(得分:1)

至于我,我排除了以下属性,问题就消失了

<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>

答案 7 :(得分:0)

但是,这是一个非常讨厌的问题。而不是备份整个数据库并更改hibernate.hbm2ddl.auto,可以使用面向方言的ALTER TABLE SQL。例如;对于MySQL,只需用

更新列类型
alter table your_table modify column your_column text

瞧!

PS:不要忘记更新审计表!

答案 8 :(得分:0)

在Spring / JPA / Hibernate / Postgres中,

@Type(type="org.hibernate.type.StringClobType")
String message;

对我来说就像一个魅力!

  

重要提示:数据库中的列类型对我来说没有自动更新,因此我需要允许Hibernate重新创建表,或者手动更改{{{ 1}}到varchar(255),否则出现就不会发生。

答案 9 :(得分:0)

stderr

有效,但是您必须删除 !因为在这种情况下,hibernate不会更新表。因此,您必须强制休眠以重新创建该表,该表才有效!