Cómo anotar el campo de autoincremento de MYSQL con anotaciones JPA

105

Directamente al grano, el problema es guardar el objeto Operator en MySQL DB. Antes de guardar, trato de seleccionar de esta tabla y funciona, también lo es la conexión a db.

Aquí está mi objeto Operador:

@Entity
public class Operator{

   @Id
   @GeneratedValue
   private Long id;

   private String username;

   private String password;


   private Integer active;

   //Getters and setters...
}

Para salvar utilizo EntityManagerel persistmétodo de JPA .

Aquí hay un registro:

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

A mi modo de ver, el problema es la configuración con incremento automático, pero no puedo averiguar dónde.

Probé algunos trucos que he visto aquí: Hibernate no respeta el campo de clave primaria auto_increment de MySQL Pero nada de eso funcionó

Si se necesitan otros archivos de configuración, se los proporcionaré.

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
fuente
¿Qué versión de Hibernate estás usando?
Steven Benitez

Respuestas:

150

Para usar una AUTO_INCREMENTcolumna MySQL , se supone que debe usar una IDENTITYestrategia:

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

Que es lo que obtendría al usar AUTOcon MySQL:

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

Lo que en realidad es equivalente a

@Id @GeneratedValue
private Long id;

En otras palabras, su mapeo debería funcionar. Pero Hibernate debería omitir la idcolumna en la declaración de inserción de SQL, y no es así. Debe haber una especie de desajuste en alguna parte.

¿Especificó un dialecto MySQL en su configuración de Hibernate (probablemente MySQL5InnoDBDialectoMySQL5Dialect dependiendo del motor que esté usando)?

Además, ¿quién creó la mesa? ¿Puede mostrar el DDL correspondiente?

Seguimiento: no puedo reproducir su problema. Usando el código de su entidad y su DDL, Hibernate genera el siguiente SQL (esperado) con MySQL:

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

Tenga en cuenta que la idcolumna está ausente de la declaración anterior, como se esperaba.

En resumen, su código, la definición de la tabla y el dialecto son correctos y coherentes, debería funcionar. Si no es así para usted, tal vez algo no esté sincronizado (haga una compilación limpia, revise el directorio de compilación, etc.) o algo más no esté bien (revise los registros para ver si hay algo sospechoso).

En cuanto al dialecto, la única diferencia entre MySQL5Dialecto MySQL5InnoDBDialectes que el último agrega ENGINE=InnoDBobjetos a la tabla al generar el DDL. Usar uno u otro no cambia el SQL generado.

Pascal Thivent
fuente
Pascal, tienes razón en eso, pero algo en mis archivos de configuración no está bien. ¿Alguna otra sugerencia, tal vez, ahora que he puesto nueva información y archivos de configuración?
trivunm
9
@Pascal: descubrí que necesitaba @GeneratedValue (estrategia = GenerationType.IDENTITY) para que AUTO_INCREMENT funcione correctamente al usar JPA 2 / Hibernate 4.0.0.CR2 / JBoss AS 7. bit.ly/tdNyOJ
Joshua Davis
4
Tenga en cuenta que eso es cierto para MySQL . Con PostgreSQL no obtienes @GeneratedValue(strategy=GenerationType.IDENTITY)cuando escribes @GeneratedValue(strategy=GenerationType.AUTO)y @GeneratedValue. Así que tenga cuidado y trate de ser detallado.
SajjadG
nota: con versiones más recientes de Hibernate y / o MySQL / MariaDB GenerationType.AUTO se establecerá por defecto en GenerationType.TABLE. Lo que al actualizar puede provocar problemas desagradables con secuencias desincronizadas.
Jwenting el
no olvide recrear la tabla: spring.jpa.hibernate.ddl-auto = create. Con la actualización no funcionará
Glasnhost
38

Usando MySQL, solo este enfoque funcionó para mí:

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

Los otros 2 enfoques declarados por Pascal en su respuesta no me funcionaron.

Jelle
fuente
Sí, arbitré esto en mi pregunta / respuesta. stackoverflow.com/questions/39675714/…
Yan Khonski
Gracias, funciona para mí, lo estoy usando JPAcon spring-boot y MySQL.
Osama Al-Banna
12

Para cualquiera que lea esto y esté usando EclipseLink para JPA 2.0, aquí están las dos anotaciones que tuve que usar para que JPA persistiera los datos, donde "MySequenceGenerator" es el nombre que quiera darle al generador, "myschema" es el nombre del esquema en su base de datos que contiene el objeto de secuencia, y "mysequence" es el nombre del objeto de secuencia en la base de datos.

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

Para aquellos que usan EclipseLink (y posiblemente otros proveedores de JPA), es CRÍTICO que establezca el atributo deploymentSize para que coincida con el valor INCREMENT definido para su secuencia en la base de datos. Si no lo hace, obtendrá una falla de persistencia genérica y perderá mucho tiempo tratando de rastrearlo, como hice yo. Aquí está la página de referencia que me ayudó a superar este desafío:

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

Además, para dar contexto, esto es lo que estamos usando:

Java 7 Glassfish 3.1 PostgreSQL 9.1 PrimeFaces 3.2 / JSF 2.1

Además, por el bien de la pereza, construí esto en Netbeans con los asistentes para generar Entidades de DB, Controladores de Entidades y JSF de Entidades, y los asistentes (obviamente) no saben cómo lidiar con columnas de ID basadas en secuencia, así que tendrá que agregar manualmente estas anotaciones.

Max impresionante
fuente
6

Si está usando Mysql con Hibernate v3, está bien usarlo GenerationType.AUTOporque internamente lo usará GenerationType.IDENTITY, que es el más óptimo para MySQL.

Sin embargo, en Hibernate v5, ha cambiado. GenerationType.AUTOutilizará lo GenerationType.TABLEque genera muchas consultas para la inserción.

Puede evitar eso usando GenerationType.IDENTITY(si MySQL es la única base de datos que está usando) o con estas notaciones (si tiene varias bases de datos):

@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
dmarquina
fuente
sí, una causa complicada de algunos errores de regresión desagradables al actualizar su aplicación Spring, que bajo el capó también actualiza Hibernate.
Jwenting el
5

Asegúrese de que el tipo de datos de identificación sea Long en lugar de String, si eso será una cadena, la anotación @GeneratedValue no funcionará y la generación de sql para

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

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

eso necesita ser

create table VMS_AUDIT_RECORDS (id **bigint** not null auto_increment primary key (id))
ABHAY JOHRI
fuente
1

Intenté todo, pero aún así no pude hacer eso, estoy usando mysql, jpa con hibernate, resolví mi problema asignando el valor de id 0 en el constructor A continuación está mi código de declaración de id

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

Como ha definido la identificación en el tipo int en la creación de la base de datos, también debe usar el mismo tipo de datos en la clase del modelo. Y como ha definido el ID para que aumente automáticamente en la base de datos, debe mencionarlo en la clase del modelo pasando el valor 'GenerationType.AUTO' en el atributo 'estrategia' dentro de la anotación @GeneratedValue. Entonces el código se convierte en el siguiente.

@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
fuente
1

Igual que respondió pascal, solo si necesita usar .AUTO por alguna razón, solo necesita agregar las propiedades de su aplicación:

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