23

私のエンティティの 1 つに、MachineryというStringプロパティがありますnotes。JPA 2-Hibernate がスキーマを生成します。私の場合、RDBMS は MySQL です。

notes列として作成されVARCHAR(255)ます。これは正しいです。

ユーザーはレコードの作成を開始し、すべてが完全に機能しますが、悪名高いData too long for column "notes"エラーが発生するユーザーもいます。

そのフィールドには、ユーザーの機械に関するメモを入れるのに十分なスペースがありません! わかりました、問題ありません。スキーマを変更しよう!

そこで、エンティティ クラスを開き、プロパティを次のように変更します。

@Column(length=1000000)
@Lob
private String notes;

ちなみに、私のpersistence.xml宣言:

<property name="hibernate.hbm2ddl.auto" value="update" />

notesアプリケーションの再起動後、Hibernate が私の列を a に変更してくれたことをうれしく思いますLONGTEXT(私には十分です)。

そのため、最初にアプリケーションを使用して新しい「長いメモ」レコードを作成しようとしましたが、今でも「データが長すぎます」というエラーが表示されますLONGTEXT

INSERT次に、 MySQL コマンド ラインからraw を実行してみましたが、うまくいきました。そのフィールドに長いメモを挿入できます!

最後にDROP、ローカル/ステージング DB スキーマを変更hibernate.hbm2ddl.autoするpersistence.xmlcreate、機能します。

JPAはまだそれがであると考えていVARCHARますか? ある種のキャッシュまたはスキーマの情報を格納する場所はありますか?

明らかに、本番データベースを削除できません。では、列の種類をリセットまたは変更するにはどうすればよいでしょうか?

JBossAS7 JPA 2-Hibernate を使用しています。

4

10 に答える 10

25

決定的なHibernateの本「Java persistence with Hibernate」は、 hibernate.hbm2ddl.autoの更新値についてこれに言及しています(太字は私のものです)

この構成プロパティの追加オプションである update は、開発中に役立ちます。組み込みの SchemaUpdate ツールが有効になり、スキーマの進化が容易になります。有効にすると、Hibernate は起動時に 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;
  }

}

私の永続性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 の値を変更してエンティティのテキスト プロパティを作成し、これに変更すると、

.....

  @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) から 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

ただし、更新を使用していて、プロパティを変更する代わりに、別のプロパティの場所を追加すると、正しい SQL が再度生成されます。

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

したがって、本質的に、作成 (最初にテーブルを削除してから再作成する) は正しく機能しますが、プロパティ メタデータに変更がある場合、更新は機能しません。

私には、インクリメンタル アップデートのドライバー サポートの問題がここで発生しているように見えます。これも直感的に考えると、列のデータ型の更新をサポートしても意味がありません。変更された列のデータ型が以前のデータ型の縮小バージョンである場合、既存のデータはどうなりますか。

于 2012-09-13T11:24:46.190 に答える
20

私はこの問題を抱えていました。これを読んだ後、答えを見つけました。考えてみれば非常に論理的であり、enversの監査されたテーブルに関連しています。

再現方法

  • あなたは休止状態のenversを使用しています
  • 注釈 @Lob を追加して、コード内の列の型を変更します。

原因

Hibernate は元のテーブルのみを更新し、監査されたテーブルは更新しません。これが hibernate の機能です。

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

症状

MysqlDataTruncation 例外は、悪名高い「列 'x' のデータが長すぎます」で発生します。

解決

監査対象テーブルのタイプを手動で更新します。例:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

または、次のように列定義を更新することもできます (スキーマを削除して再作成しても構わない場合)。

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

例外はテーブルの名前ではなく列の名前だけを言うため、これは非常に注意が必要でした!!、そのため、スキーマの削除と再作成も機能し、監査されたテーブルが再生成されます。

于 2015-08-03T01:30:37.133 に答える
3

なし!- DB バックアップ - hbm2ddl => CREATE-DROP - hbm2ddl => UPDATE - DB 復元

クレイジー!:(

于 2012-10-12T13:30:52.900 に答える
1

私としては、次のプロパティを除外すると問題が解決します

<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
于 2014-10-20T03:59:33.183 に答える
0

Spring/JPA/Hibernate/Postgres では、

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

私にとって魅力のように機能します!

重要な注意: データベースの列の型は自動更新されないため、Hibernate がテーブルを再作成できるようにするか、手動で型を から に変更する必要がありますvarchar(255)textそうしないと、何も起こらないように見えます

于 2016-07-30T13:53:02.860 に答える
0

かなり悩ましい問題ですが。DB全体をバックアップして変更する代わりにhibernate.hbm2ddl.auto、方言指向のALTER TABLESQLを使用できます。例えば; MySQLの場合、列タイプを更新するだけです

alter table your_table modify column your_column text

そして出来上がり!

PS: 監査テーブルを更新することを忘れないでください!

于 2014-11-10T14:04:52.363 に答える