Comment annoter le champ d'auto-incrémentation MYSQL avec des annotations JPA

106

Droit à l'essentiel, le problème est de sauvegarder l'objet Operator dans MySQL DB. Avant d'enregistrer, j'essaie de sélectionner dans ce tableau et cela fonctionne, tout comme la connexion à db.

Voici mon objet Operator:

@Entity
public class Operator{

   @Id
   @GeneratedValue
   private Long id;

   private String username;

   private String password;


   private Integer active;

   //Getters and setters...
}

Pour enregistrer, j'utilise EntityManagerla persistméthode de JPA .

Voici un journal:

Hibernate: insert into Operator (active, password, username, id) values (?, ?, ?, ?)
com.mysql.jdbc.JDBC4PreparedStatement@15724a0: insert into Operator (active,password, username, id) values (0, 'pass', 'user', ** NOT SPECIFIED **)

À mon avis, le problème est la configuration avec incrémentation automatique, mais je ne sais pas où.

J'ai essayé quelques astuces que j'ai vues ici: Hibernate ne respecte pas le champ de clé primaire auto_increment de MySQL Mais rien de tout cela n'a fonctionné

Si d'autres fichiers de configuration sont nécessaires, je les fournirai.

DDL:

CREATE TABLE `operator` ( 
`id` INT(10) NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(40) NOT NULL,
`last_name` VARCHAR(40) NOT NULL,
`username` VARCHAR(50) NOT NULL,
`password` VARCHAR(50) NOT NULL,
`active` INT(1) NOT NULL,
PRIMARY KEY (`id`)
)
trivunm
la source
Quelle version d'Hibernate utilisez-vous?
Steven Benitez

Réponses:

150

Pour utiliser une AUTO_INCREMENTcolonne MySQL , vous êtes censé utiliser une IDENTITYstratégie:

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;

C'est ce que vous obtiendrez en utilisant AUTOMySQL:

@Id @GeneratedValue(strategy=GenerationType.AUTO)
private Long id;

Ce qui est en fait équivalent à

@Id @GeneratedValue
private Long id;

En d'autres termes, votre cartographie devrait fonctionner. Mais Hibernate devrait omettre la idcolonne dans l'instruction d'insertion SQL, et ce n'est pas le cas. Il doit y avoir une sorte de décalage quelque part.

Avez-vous spécifié un dialecte MySQL dans votre configuration Hibernate (probablement MySQL5InnoDBDialectouMySQL5Dialect selon le moteur que vous utilisez)?

De plus, qui a créé la table? Pouvez-vous montrer le DDL correspondant?

Suivi: je ne peux pas reproduire votre problème. En utilisant le code de votre entité et votre DDL, Hibernate génère le SQL suivant (attendu) avec MySQL:

insert 
into
    Operator
    (active, password, username) 
values
    (?, ?, ?)

Notez que la idcolonne est absente de l'instruction ci-dessus, comme prévu.

Pour résumer, votre code, la définition de la table et le dialecte sont corrects et cohérents, cela devrait fonctionner. Si ce n'est pas pour vous, peut-être que quelque chose n'est pas synchronisé (faites une compilation propre, vérifiez le répertoire de construction, etc.) ou quelque chose d'autre est tout simplement faux (vérifiez les journaux pour tout ce qui est suspect).

En ce qui concerne le dialecte, la seule différence entre MySQL5Dialectou MySQL5InnoDBDialectest que ce dernier ajoute ENGINE=InnoDBaux objets de la table lors de la génération du DDL. L'utilisation de l'un ou de l'autre ne change pas le SQL généré.

Pascal Thivent
la source
Pascal, vous avez raison, mais quelque chose dans mes fichiers de configuration ne va pas. D'autres suggestions peut-être, maintenant que j'ai mis de nouvelles informations et des fichiers de configuration?
trivunm
9
@Pascal - J'ai trouvé que j'avais besoin de @GeneratedValue (strategy = GenerationType.IDENTITY) pour que AUTO_INCREMENT fonctionne correctement lors de l'utilisation de JPA 2 / Hibernate 4.0.0.CR2 / JBoss AS 7. bit.ly/tdNyOJ
Joshua Davis
4
Notez que c'est vrai pour MySQL . Avec PostgreSQL, vous n'obtenez pas @GeneratedValue(strategy=GenerationType.IDENTITY)lorsque vous écrivez @GeneratedValue(strategy=GenerationType.AUTO)et @GeneratedValue. Soyez donc prudent et essayez d'être verbeux.
sajjadG du
Remarque: avec les versions plus récentes d'Hibernate et / ou MySQL / MariaDB GenerationType.AUTO sera par défaut GenerationType.TABLE. Ce qui lors de la mise à niveau peut entraîner des problèmes désagréables avec des séquences désynchronisées.
jwenting le
n'oubliez pas de recréer la table: spring.jpa.hibernate.ddl-auto = create. Avec la mise à jour, cela ne fonctionnera pas
Glasnhost
38

En utilisant MySQL, seule cette approche fonctionnait pour moi:

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;

Les 2 autres approches énoncées par Pascal dans sa réponse ne fonctionnaient pas pour moi.

Jelle
la source
Ouais, je l'ai référencé dans ma question / réponse. stackoverflow.com/questions/39675714/…
Yan Khonski
Merci, ça marche pour moi, j'utilise JPAavec spring-boot et MySQL.
Osama Al-Banna
12

Pour tous ceux qui lisent ceci qui utilisent EclipseLink for JPA 2.0, voici les deux annotations que j'ai dû utiliser pour que JPA conserve les données, où "MySequenceGenerator" est le nom que vous voulez donner au générateur, "myschema" est le nom du schéma dans votre base de données qui contient l'objet séquence, et "mysequence" est le nom de l'objet séquence dans la base de données.

@GeneratedValue(strategy= GenerationType.SEQUENCE, generator="MySequenceGenerator")
@SequenceGenerator(allocationSize=1, schema="myschema",  name="MySequenceGenerator", sequenceName = "mysequence")

Pour ceux qui utilisent EclipseLink (et éventuellement d'autres fournisseurs JPA), il est CRITIQUE que vous définissiez l'attribut allocationSize pour qu'il corresponde à la valeur INCREMENT définie pour votre séquence dans la base de données. Sinon, vous obtiendrez un échec de persistance générique et perdrez beaucoup de temps à essayer de le retrouver, comme je l'ai fait. Voici la page de référence qui m'a aidé à surmonter ce défi:

http://wiki.eclipse.org/EclipseLink/Examples/JPA/PrimaryKey#Using_Sequence_Objects

Aussi, pour donner du contexte, voici ce que nous utilisons:

Java 7 Glassfish 3.1 PostgreSQL 9.1 PrimeFaces 3.2 / JSF 2.1

De plus, par paresse, j'ai construit cela dans Netbeans avec les assistants pour générer des entités à partir de DB, des contrôleurs à partir d'entités et JSF à partir d'entités, et les assistants (évidemment) ne savent pas comment gérer les colonnes d'ID basées sur des séquences, donc vous devrez ajouter manuellement ces annotations.

Max génial
la source
6

Veuillez vous assurer que le type de données id est Long au lieu de String, si ce sera une chaîne, l'annotation @GeneratedValue ne fonctionnera pas et la génération SQL pour

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private String id;

create table VMS_AUDIT_RECORDS (id **varchar(255)** not null auto_increment primary key (id))

cela doit être

create table VMS_AUDIT_RECORDS (id **bigint** not null auto_increment primary key (id))
ABHAY JOHRI
la source
6

Si vous utilisez Mysql avec Hibernate v3, vous pouvez l'utiliser GenerationType.AUTOcar en interne, il utiliseraGenerationType.IDENTITY , ce qui est le plus optimal pour MySQL.

Cependant, dans Hibernate v5, cela a changé. GenerationType.AUTOutilisera GenerationType.TABLEce qui génère trop de requêtes pour l'insertion.

Vous pouvez éviter cela en utilisant GenerationType.IDENTITY(si MySQL est la seule base de données que vous utilisez) ou avec ces notations (si vous avez plusieurs bases de données):

@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
dmarquina
la source
oui, cause délicate de mauvaises erreurs de régression lors de la mise à niveau de votre application Spring qui sous le capot met également à niveau Hibernate.
jwenting le
1

J'ai tout essayé, mais je n'ai toujours pas pu le faire, j'utilise mysql, jpa avec hibernate, j'ai résolu mon problème en attribuant la valeur de l'id 0 ​​dans le constructeur Voici mon code de déclaration d'id

@Id
@Column(name="id",updatable=false,nullable=false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
M. Waseem Ullah Khan
la source
1

Comme vous avez défini l'id dans le type int lors de la création de la base de données, vous devez également utiliser le même type de données dans la classe de modèle. Et comme vous avez défini l'identifiant à incrémenter automatiquement dans la base de données, vous devez le mentionner dans la classe de modèle en passant la valeur «GenerationType.AUTO» dans l'attribut «stratégie» dans l'annotation @GeneratedValue. Ensuite, le code devient comme ci-dessous.

@Entity
public class Operator{

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private int id;

  private String username;

  private String password;

  private Integer active;

  //Getters and setters...
}
Anjali Pavithra
la source
1

comme pascal a répondu, juste si vous devez utiliser .AUTO pour une raison quelconque, il vous suffit d'ajouter les propriétés de votre application:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto = update
Jorge
la source
0

pouvez-vous vérifier si vous vous êtes connecté à la bonne base de données. car j'ai été confronté au même problème, mais j'ai finalement trouvé que je me connectais à une base de données différente.

identity prend en charge les colonnes d'identité dans DB2, MySQL, MS SQL Server, Sybase et HypersonicSQL. L'identifiant renvoyé est de type long, short ou int.

Plus d'infos: http://docs.jboss.org/hibernate/orm/3.5/reference/en/html/mapping.html#mapping-declaration-id

Mohan Reddy
la source