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

Fab*_* B. 13 hibernate jpa longtext

我的一个实体Machinery有一个String叫做的财产notes.JPA 2-Hibernate为我生成模式,在我的例子中,RDBMS是MySQL.

notes是作为VARCHAR(255)列创建的,这是正确的.

用户开始创建记录并且所有工作都完美无缺,但随后一些用户会收到臭名昭着的Data too long for column "notes"错误.

那个领域没有足够的空间供用户的机器笔记!好的,没问题.让我们改变架构!

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

@Column(length=1000000)
@Lob
private String notes;
Run Code Online (Sandbox Code Playgroud)

顺便persistence.xml说一句,我声明:

<property name="hibernate.hbm2ddl.auto" value="update" />
Run Code Online (Sandbox Code Playgroud)

应用程序重启后,我很高兴Hibernate正在改变我的notes专栏LONGTEXT(对我来说已经足够了).

所以我首先尝试使用我的应用程序来创建一个新的"长期记录"记录,我仍然是错误"数据太长",虽然LONGTEXT现在是.

然后,我尝试INSERT从MySQL命令行做一个原始的,它的工作原理!我可以在该字段中插入长音符!

最后,我DROP在我的本地/分期DB模式,改变hibernate.hbm2ddl.autopersistence.xmlcreate和它的作品.

JPA是否仍然认为它是一个VARCHAR?它是否有某种缓存或存储架构信息的某个位置?

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

我正在使用JBossAS7 JPA 2-Hibernate.

Sha*_*dra 20

最新的Hibernate书"Java持久性与Hibernate"提到了关于hibernate.hbm2ddl.auto更新值(粗体是我的)

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

Hibernate也文档建议同样在这里

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;
  }

}
Run Code Online (Sandbox Code Playgroud)

我的持久性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>
Run Code Online (Sandbox Code Playgroud)

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

.....

  @Column( length = 255 )
  private String text;
......
Run Code Online (Sandbox Code Playgroud)

架构生成器在启动时生成以下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
Run Code Online (Sandbox Code Playgroud)

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

.....
@Lob
@Column( length = 100000 )
private String text;
.......
Run Code Online (Sandbox Code Playgroud)

现在生成了正确的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
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.

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

 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


Zoo*_*MMX 8

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

如何重现

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

原因

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

ALTER TABLE piece_aud MODIFY notes LONGTEXT;
Run Code Online (Sandbox Code Playgroud)

症状

臭名昭着的"数据太长,列'x'"引发了MysqlDataTruncation异常.

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

ALTER TABLE piece_aud MODIFY notes LONGTEXT;
Run Code Online (Sandbox Code Playgroud)

这非常棘手,因为异常只说明了列的名称而不是表的名称!!这就是为什么drop和重新创建模式也可以工作,导致审计表被重新生成.

  • 完全忘记了审计表!你拯救了这一天 (2认同)

Rah*_*pta 5

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

@Column(name="your_column_name",columnDefinition="LONGTEXT")
private String notes;
Run Code Online (Sandbox Code Playgroud)

我知道很久以前有人问过这个问题,但这仍然可能对某人有所帮助。:)


Fab*_* B. 3

没有什么!我最终得到: - 数据库备份 - hbm2ddl => CREATE-DROP - hbm2ddl => 更新 - 数据库恢复

疯狂的!:(