137 votes

Comment annoter un champ MYSQL autoincrement avec des annotations JPA ?

Pour aller droit au but, le problème est de sauvegarder l'objet Operator dans la base de données MySQL. Avant de sauvegarder, j'essaie de sélectionner à partir de cette table et cela fonctionne, de même que la connexion à la base de données.

Voici mon objet Opérateur :

@Entity
public class Operator{

   @Id
   @GeneratedValue
   private Long id;

   private String username;

   private String password;

   private Integer active;

   //Getters and setters...
}

Pour économiser, j'utilise JPA EntityManager 's persist méthode.

Voici un extrait du 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 **)

De mon point de vue, le problème se situe au niveau de la configuration et de l'incrémentation automatique, mais je n'arrive pas à savoir où.

J'ai essayé quelques astuces que j'ai vues ici : Hibernate ne respecte pas le champ clé primaire auto_incrémenté 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`)
)

189voto

Pascal Thivent Points 295221

Pour utiliser un serveur MySQL AUTO_INCREMENT vous êtes censé utiliser une colonne IDENTITY stratégie :

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

C'est ce que l'on obtient en utilisant AUTO avec MySQL :

@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 doit fonctionner. Mais Hibernate devrait omettre l'élément id dans l'instruction d'insertion SQL, et ce n'est pas le cas. Il doit y avoir une sorte d'incompatibilité quelque part.

Avez-vous spécifié un dialecte MySQL dans votre configuration Hibernate (probablement MySQL5InnoDBDialect o MySQL5Dialect selon le moteur utilisé) ?

Par ailleurs, qui a créé le tableau ? Pouvez-vous montrer le DDL correspondant ?

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

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

Il convient de noter que le id est absente de la déclaration ci-dessus, comme prévu.

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

En ce qui concerne le dialecte, le seulement différence entre MySQL5Dialect ou MySQL5InnoDBDialect est que cette dernière ajoute ENGINE=InnoDB aux objets de la table lors de la génération du DDL. L'utilisation de l'un ou l'autre ne modifie pas le code SQL généré.

52voto

Jelle Points 651

En utilisant MySQL, seule cette approche fonctionnait pour moi :

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

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

13voto

Max Awesome Points 71

Pour tous ceux qui lisent ceci et qui utilisent EclipseLink pour JPA 2.0, voici les deux annotations que j'ai dû utiliser pour que JPA persiste 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 de définir l'attribut allocationSize de manière à ce qu'il corresponde à la valeur INCREMENT définie pour votre séquence dans la base de données. Si vous ne le faites pas, 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

Par ailleurs, pour situer le 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 ceci dans Netbeans avec les assistants de génération d'entités à partir de la base de données, de contrôleurs à partir d'entités et de JSF à partir d'entités, et les assistants (évidemment) ne savent pas comment traiter les colonnes d'ID basées sur la séquence, de sorte que vous devrez ajouter manuellement ces annotations.

9voto

dmarquina Points 550

Si vous utilisez Mysql avec Hibernate v3, vous pouvez utiliser GenerationType.AUTO parce qu'en interne, il utilisera GenerationType.IDENTITY qui est le plus optimal pour MySQL.

Cependant, dans Hibernate v5, cela a changé. GenerationType.AUTO utilisera GenerationType.TABLE ce 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")

7voto

ABHAY JOHRI Points 528

Assurez-vous que le type de données de l'identifiant est Long au lieu de String, si c'est le cas. est une chaîne de caractères, l'annotation @GeneratedValue ne fonctionnera pas et l'annotation @GeneratedValue ne fonctionnera pas. sql générant pour

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

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

qui doit être

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X