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.
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! :(
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?.
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.
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;
L'exception MysqlDataTruncation est déclenchée avec le fameux "Données trop longues pour la colonne 'x'".
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.
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é.
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. :)
Je pense que cela résout le problème @Column(columnDefinition="LONGVARCHAR")
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"/>
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.
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!