web-dev-qa-db-fra.com

JPA: "Les données trop longues pour la colonne" ne changent pas

Une de mes entités Machinery a une propriété String appelée notes. JPA 2-Hibernate génère le schéma pour moi, dans mon cas, le SGBDR est un MySQL.

notes est créé sous la forme d'une colonne VARCHAR(255), ce qui est correct.

Les utilisateurs commencent à créer des enregistrements et tout fonctionne parfaitement, mais ensuite certains utilisateurs obtiennent la fameuse erreur Data too long for column "notes".

Ce champ n'a pas assez de place pour les notes de machines de l'utilisateur! Ok, pas de problème. Changeons le schéma!

Alors, j'ouvre ma classe d'entités et change ma propriété en:

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

Au fait, mon persistence.xml déclare:

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

Après le redémarrage d'une application, je suis heureux que Hibernate modifie ma colonne notes en une LONGTEXT (cela me suffit).

J'ai donc d'abord essayé d'utiliser mon application pour créer un nouvel enregistrement "noté long" et j'ai toujours l'erreur "Données trop longues" bien que ce soit une LONGTEXT maintenant.

Ensuite, j'essaie de faire une INSERT brute à partir de la ligne de commande MySQL et cela fonctionne! Je peux insérer de longues notes dans ce champ! 

Enfin, je DROP mon schéma de base de données local/intermédiaire et change hibernate.hbm2ddl.auto dans persistence.xml en create et cela fonctionne.

JPA pense-t-il toujours qu'il s'agit d'une VARCHAR? At-il une sorte de cache ou un endroit dans lequel il stocke les informations de schéma?

Je ne peux évidemment pas laisser tomber ma base de données de production. Alors, que puis-je faire pour réinitialiser ou changer le type de colonne?

J'utilise JBossAS7 JPA 2-Hibernate.

11
Fabio B.

RIEN! J'ai fini avec: - Sauvegarde de la base de données - hbm2ddl => CREATE-DROP - hbm2ddl => MISE À JOUR - Restauration de la base de données

Fou! :(

3
Fabio B.

Le livre définitif d'Hibernate "Persistance Java avec Hibernate" mentionne ceci à propos de update valeur pour hibernate.hbm2ddl.auto (les caractères gras sont les miens)

Une option supplémentaire pour cette propriété de configuration, update, peut être Utile lors du développement: elle active l'outil intégré SchemaUpdate, , Qui peut faciliter l'évolution du schéma. Si activé, Hibernate lit Les métadonnées de la base de données JDBC au démarrage et crée de nouvelles tables et des contraintes En comparant l'ancien schéma avec les métadonnées de mappage actuelles . Notez que cette fonctionnalité dépend de la qualité des métadonnées Fournies par le pilote JDBC, domaine dans lequel de nombreux pilotes Manquent . En pratique, cette fonctionnalité est donc moins excitante et Utile qu’elle n’apparaît.

Les documents d'Hibernate suggèrent également la même chose ici

L'outil SchemaUpdate mettra à jour un schéma existant avec des modifications "incrémentielles" de . SchemaUpdate dépend de l'API de métadonnées De JDBC et, en tant que telle, ne fonctionnera pas avec tous les pilotes JDBC.

J'ai essayé de reproduire votre cas d'utilisation et j'ai trouvé ça surprenant que moi aussi j'avais ce problème.

J'ai une entité utilisateur comme celle-ci

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

}

et ma persistance xml est comme ça

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

Si je change la valeur de hibernate.hbm2ddl.auto pour créer et changer la propriété text de entity en this

.....

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

Le générateur de schéma génère les fichiers sql suivants au démarrage

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

Maintenant changer à nouveau la propriété dans l'entité

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

Maintenant, le code SQL correct est généré

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

Jusqu'ici tout va bien.

Maintenant, si je change la valeur hibernate.hbm2ddl.auto pour mettre à jour et répète le changement d’entité ci-dessus dans le même ordre, aucune colonne de mise à jour sql n’est générée malgré le fait que j’ai mis à jour la colonne de texte de varchar (255) vers 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

Cependant, si j'utilise update et à la place pour modifier une propriété, j'ajoute un autre emplacement de propriété, puis le code SQL correct est généré à nouveau.

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

Donc, essentiellement, la création (qui supprime d'abord la table puis la recrée) fonctionne correctement, mais la mise à jour ne fonctionne pas s'il y a une modification dans les métadonnées de la propriété.

Pour moi, il semble que la question de la prise en charge des pilotes pour les mises à jour incrémentielles soit en jeu. Aussi intuitivement Si j'y réfléchis, cela n'a aucun sens de donner un support pour mettre à jour le type de données des colonnes. Qu'adviendra-t-il des données existantes si le type de données de la colonne modifié est une version réduite du type de données précédent?.

20
Shailendra

Je viens d'avoir ce problème, après avoir lu cela, j'ai trouvé la réponse, c'est très logique si vous y réfléchissez, est lié aux tables d'audit vérifiées.

Comment se reproduire

  • Vous utilisez hibernate envers
  • Vous modifiez le type d'une colonne dans le code en ajoutant l'annotation @Lob. 

Cause

Hibernate ne met à jour que la table d'origine, pas celle auditée, voici ce que fait Hibernate:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

Symptômes

L'exception MysqlDataTruncation est déclenchée avec le fameux "Données trop longues pour la colonne 'x'".

Solution

Mettez à jour manuellement le type de la table auditée. Exemple:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

C'était très délicat, car l'exception ne dit que le nom de la colonne et non le nom de la table !!, c'est pourquoi supprimer et recréer le schéma fonctionne également car les tables auditées sont régénérées.

7
ZooMMX

J'avais le même problème. L'instruction INSTER fonctionnait parfaitement directement sur la base de données, mais le faire via Hibernate ne fonctionnait pas et produisait une troncature des données: données trop longues pour la colonne. Tout a fonctionné lorsque hbm2ddl a été modifié pour créer-déposer.

Mais mon vrai problème était dû à l'utilisation de tables d'audit à l'aide de la fonctionnalité d'audit intégrée à Hibernate. La table principale a été mise à jour correctement avec la taille augmentée mais pas la table d'audit, de sorte que toutes les modifications écrites dans la table d'audit ont provoqué cette erreur de troncature de données. Il suffit de mettre à jour manuellement la colonne dans le tableau d’audit à la taille appropriée et tout a bien fonctionné.

4
BeCodeMonkey

Moi aussi j'ai eu le même scénario, et ci-dessous on travaille bien pour moi

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

Je sais que cela a été demandé il y a longtemps, mais cela pourrait quand même aider quelqu'un. :)

3
Rahul Gupta

Je pense que cela résout le problème @Column(columnDefinition="LONGVARCHAR")

3
Priyanka

Quant à moi, j'exclus les propriétés suivantes et le problème disparaît

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

Au printemps/JPA/Hibernate/Postgres,

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

Fonctionne comme un charme pour moi!

Remarque importante : Le type de colonne dans la base de données ne se met pas à jour automatiquement. Je dois donc autoriser Hibernate à recréer la table ou modifier manuellement le type de varchar(255) à text, sinon rien apparaît. arriver.

0
Spider

Problème assez ennuyant, cependant. Au lieu de sauvegarder l'intégralité de la base de données et de modifier le code hibernate.hbm2ddl.auto, vous pouvez utiliser des instructions SQL ALTER TABLE axées sur le dialecte. Par exemple; pour MySQL vient de mettre à jour le type de colonne avec

alter table your_table modify column your_column text

et le tour est joué!

PS: Ne pas oublier de mettre à jour les tables d'audit!

0
tugcem