Come annotare il campo di incremento automatico MYSQL con annotazioni JPA


106

Dritto al punto, il problema è salvare l'oggetto Operator nel database MySQL. Prima di salvare, provo a selezionare da questa tabella e funziona, così come la connessione a db.

Ecco il mio oggetto Operatore:

@Entity
public class Operator{

   @Id
   @GeneratedValue
   private Long id;

   private String username;

   private String password;


   private Integer active;

   //Getters and setters...
}

Per salvare utilizzo EntityManageril persistmetodo di JPA .

Ecco alcuni log:

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

Per come la vedo io, il problema è la configurazione con incremento automatico ma non riesco a capire dove.

Ho provato alcuni trucchi che ho visto qui: Hibernate non rispetta il campo della chiave primaria auto_increment di MySQL Ma niente di tutto ciò ha funzionato

Se sono necessari altri file di configurazione, li fornirò.

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

Quale versione di Hibernate stai usando?
Steven Benitez

Risposte:


150

Per utilizzare una AUTO_INCREMENTcolonna MySQL , dovresti utilizzare una IDENTITYstrategia:

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

Che è ciò che otterresti usando AUTOcon MySQL:

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

Che in realtà è equivalente a

@Id @GeneratedValue
private Long id;

In altre parole, la tua mappatura dovrebbe funzionare. Ma Hibernate dovrebbe omettere la idcolonna nell'istruzione SQL insert, e non lo è. Deve esserci una sorta di discrepanza da qualche parte.

Hai specificato un dialetto MySQL nella configurazione di Hibernate (probabilmente MySQL5InnoDBDialecto a MySQL5Dialectseconda del motore che stai utilizzando)?

Inoltre, chi ha creato il tavolo? Puoi mostrare il DDL corrispondente?

Follow-up: non riesco a riprodurre il tuo problema. Utilizzando il codice della tua entità e del tuo DDL, Hibernate genera il seguente SQL (previsto) con MySQL:

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

Notare che la idcolonna è assente dall'istruzione precedente, come previsto.

Per riassumere, il tuo codice, la definizione della tabella e il dialetto sono corretti e coerenti, dovrebbe funzionare. In caso contrario, forse qualcosa non è sincronizzato (esegui una build pulita, ricontrolla la directory di build, ecc.) O qualcos'altro è semplicemente sbagliato (controlla i log per qualsiasi cosa sospetta).

Per quanto riguarda il dialetto, l' unica differenza tra MySQL5Dialecto MySQL5InnoDBDialectè che quest'ultimo aggiunge ENGINE=InnoDBagli oggetti della tabella durante la generazione del DDL. L'uso dell'uno o dell'altro non cambia l'SQL generato.


Pascal, hai ragione su questo, ma qualcosa nei miei file di configurazione non è giusto. Qualche altro suggerimento forse, ora che ho inserito nuove informazioni e file di configurazione?
trivunm

9
@Pascal - Ho scoperto che avevo bisogno di @GeneratedValue (strategy = GenerationType.IDENTITY) per far funzionare correttamente AUTO_INCREMENT quando si utilizza JPA 2 / Hibernate 4.0.0.CR2 / JBoss AS 7. bit.ly/tdNyOJ
Joshua Davis

4
Nota che è vero per MySQL . Con PostgreSQL non ottieni @GeneratedValue(strategy=GenerationType.IDENTITY)quando scrivi @GeneratedValue(strategy=GenerationType.AUTO)e @GeneratedValue. Quindi fai attenzione e cerca di essere prolisso.
sajjadG

nota: con le versioni più recenti di Hibernate e / o MySQL / MariaDB GenerationType.AUTO verrà impostato automaticamente su GenerationType.TABLE. Che durante l'aggiornamento può portare a fastidiosi problemi con sequenze non sincronizzate.
jwenting

non dimenticare di ricreare la tabella: spring.jpa.hibernate.ddl-auto = create. Con l'aggiornamento non funzionerà
Glasnhost

38

Utilizzando MySQL, solo questo approccio funzionava per me:

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

Gli altri 2 approcci dichiarati da Pascal nella sua risposta non funzionavano per me.


Sì, l'ho arbitrato nella mia domanda / risposta. stackoverflow.com/questions/39675714/...
Yan Khonski

Grazie, funziona per me, lo sto usando JPAcon spring-boot e MySQL.
Osama Al-Banna

12

Per chiunque stia leggendo questo e utilizzi EclipseLink per JPA 2.0, ecco le due annotazioni che ho dovuto utilizzare per far sì che JPA persistesse i dati, dove "MySequenceGenerator" è il nome che vuoi dare al generatore, "myschema" è il nome del schema nel database che contiene l'oggetto sequenza e "mysequence" è il nome dell'oggetto sequenza nel database.

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

Per coloro che utilizzano EclipseLink (e possibilmente altri provider JPA), è CRITICO impostare l'attributo allocationSize in modo che corrisponda al valore INCREMENT definito per la sequenza nel database. Se non lo fai, otterrai un generico errore di persistenza e sprecherai molto tempo cercando di rintracciarlo, come ho fatto io. Ecco la pagina di riferimento che mi ha aiutato a superare questa sfida:

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

Inoltre, per dare un contesto, ecco cosa stiamo usando:

Java 7 Glassfish 3.1 PostgreSQL 9.1 PrimeFaces 3.2 / JSF 2.1

Inoltre, per pigrizia, l'ho creato in Netbeans con le procedure guidate per la generazione di entità da DB, controller da entità e JSF da entità e le procedure guidate (ovviamente) non sanno come gestire le colonne ID basate su sequenza, quindi dovrai aggiungere manualmente queste annotazioni.


6

Assicurati che il tipo di dati id sia Long anziché String, se sarà una stringa, l'annotazione @GeneratedValue non funzionerà e la generazione di sql per

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

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

quello deve essere

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

6

Se stai usando Mysql con Hibernate v3 va bene usarlo GenerationType.AUTOperché internamente lo userà GenerationType.IDENTITY, che è il più ottimale per MySQL.

Tuttavia in Hibernate v5, è cambiato. GenerationType.AUTOutilizzerà GenerationType.TABLEche genera molte query per l'inserimento.

Puoi evitarlo usando GenerationType.IDENTITY(se MySQL è l'unico database che stai usando) o con queste notazioni (se hai più database):

@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")

sì, causa delicata di alcuni brutti errori di regressione durante l'aggiornamento dell'applicazione Spring che sotto il cofano aggiorna anche Hibernate.
jwenting

1

Ho provato ogni cosa, ma ancora non sono riuscito a farlo, sto usando mysql, jpa con hibernate, ho risolto il mio problema assegnando il valore di id 0 nel costruttore Di seguito è riportato il mio codice di dichiarazione id

@Id
@Column(name="id",updatable=false,nullable=false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

1

Poiché hai definito l'id in tipo int alla creazione del database, devi usare lo stesso tipo di dati anche nella classe del modello. E poiché hai definito l'id per l'incremento automatico nel database, devi menzionarlo nella classe del modello passando il valore "GenerationType.AUTO" nell'attributo "strategy" all'interno dell'annotazione @GeneratedValue. Quindi il codice diventa come di seguito.

@Entity
public class Operator{

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

  private String username;

  private String password;

  private Integer active;

  //Getters and setters...
}

1

lo stesso di pascal ha risposto, solo se devi usare .AUTO per qualche motivo devi solo aggiungere le proprietà dell'applicazione:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto = update


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.