Como anotar o campo de incremento automático MYSQL com anotações JPA


106

Direto ao ponto, o problema é salvar o objeto Operator no banco de dados MySQL. Antes de salvar, tento selecionar nesta tabela e funciona, assim como a conexão com o banco de dados.

Aqui está meu objeto Operator:

@Entity
public class Operator{

   @Id
   @GeneratedValue
   private Long id;

   private String username;

   private String password;


   private Integer active;

   //Getters and setters...
}

Para economizar, uso EntityManagero persistmétodo JPA .

Aqui está algum 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 meu ver, o problema é a configuração com incremento automático, mas não consigo descobrir onde.

Tentei alguns truques que vi aqui: Hibernate não respeitando o campo de chave primária do MySQL auto_increment Mas nada disso funcionou

Se for necessário algum outro arquivo de configuração, irei fornecê-lo.

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

Qual versão do Hibernate você está usando?
Steven Benitez

Respostas:


150

Para usar uma AUTO_INCREMENTcoluna MySQL , você deve usar uma IDENTITYestratégia:

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

Que é o que você obtém ao usar o AUTOMySQL:

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

O que é equivalente a

@Id @GeneratedValue
private Long id;

Em outras palavras, seu mapeamento deve funcionar. Mas o Hibernate deveria omitir a idcoluna na instrução de inserção SQL, e não é. Deve haver um tipo de incompatibilidade em algum lugar.

Você especificou um dialeto do MySQL na configuração do Hibernate (provavelmente MySQL5InnoDBDialectou MySQL5Dialectdependendo do mecanismo que está usando)?

Além disso, quem criou a mesa? Você pode mostrar o DDL correspondente?

Acompanhamento: Não consigo reproduzir o seu problema. Usando o código de sua entidade e seu DDL, o Hibernate gera o seguinte (esperado) SQL com MySQL:

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

Observe que a idcoluna está ausente da declaração acima, como esperado.

Resumindo, seu código, a definição da tabela e o dialeto estão corretos e coerentes, deve funcionar. Se não for para você, talvez algo esteja fora de sincronia (faça uma compilação limpa, verifique o diretório de compilação, etc.) ou outra coisa esteja simplesmente errada (verifique se há algo suspeito nos logs).

Em relação ao dialeto, a única diferença entre MySQL5Dialectou MySQL5InnoDBDialecté que este adiciona ENGINE=InnoDBà tabela objetos ao gerar o DDL. Usar um ou outro não altera o SQL gerado.


Pascal, você está certo sobre isso, mas algo em meus arquivos de configuração simplesmente não está certo. Alguma outra sugestão, talvez, agora que coloquei novas informações e arquivos de configuração?
trivunm

9
@Pascal - descobri que precisava de @GeneratedValue (strategy = GenerationType.IDENTITY) para fazer o AUTO_INCREMENT funcionar corretamente ao usar JPA 2 / Hibernate 4.0.0.CR2 / JBoss AS 7. bit.ly/tdNyOJ
Joshua Davis

4
Observe que isso é verdade para o MySQL . Com o PostgreSQL você não consegue @GeneratedValue(strategy=GenerationType.IDENTITY)quando escreve @GeneratedValue(strategy=GenerationType.AUTO)e @GeneratedValue. Portanto, tenha cuidado e tente ser prolixo.
sajjadG

nota: com versões mais recentes do Hibernate e / ou MySQL / MariaDB GenerationType.AUTO o padrão será GenerationType.TABLE. Que durante a atualização pode levar a problemas desagradáveis ​​com sequências fora de sincronia.
início de

não se esqueça de recriar a tabela: spring.jpa.hibernate.ddl-auto = create. Com atualização não vai funcionar
Glasnhost

38

Usando MySQL, apenas esta abordagem funcionou para mim:

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

As outras 2 abordagens declaradas por Pascal em sua resposta não funcionaram para mim.


Sim, referi isso na minha pergunta / resposta. stackoverflow.com/questions/39675714/…
Yan Khonski

Obrigado, funcionou para mim, estou usando JPAcom spring-boot e MySQL.
Osama Al-Banna

12

Para qualquer um que esteja lendo isso e esteja usando EclipseLink para JPA 2.0, aqui estão as duas anotações que tive que usar para fazer o JPA persistir os dados, onde "MySequenceGenerator" é qualquer nome que você deseja dar ao gerador, "myschema" é o nome do esquema em seu banco de dados que contém o objeto de sequência e "mysequence" é o nome do objeto de sequência no banco de dados.

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

Para aqueles que usam EclipseLink (e possivelmente outros provedores JPA), é CRÍTICO que você configure o atributo alocação de tamanho para corresponder ao valor INCREMENT definido para sua sequência no banco de dados. Caso contrário, você obterá uma falha de persistência genérica e perderá muito tempo tentando rastreá-la, como eu fiz. Aqui está a página de referência que me ajudou a superar este desafio:

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

Além disso, para dar contexto, aqui está o que estamos usando:

Java 7 Glassfish 3.1 PostgreSQL 9.1 PrimeFaces 3.2 / JSF 2.1

Além disso, por preguiça, eu construí isso no Netbeans com os assistentes para gerar entidades do banco de dados, controladores de entidades e JSF de entidades, e os assistentes (obviamente) não sabem como lidar com colunas de ID baseadas em sequência, então você terá que adicionar manualmente essas anotações.


6

Certifique-se de que o tipo de dados id é Long em vez de String, se for string, a anotação @GeneratedValue não funcionará e o sql gerado para

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

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

isso precisa ser

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

6

Se você estiver usando o Mysql com Hibernate v3, não há problema em usar GenerationType.AUTOporque internamente ele usará GenerationType.IDENTITY, que é o mais ideal para MySQL.

No entanto, no Hibernate v5, mudou. GenerationType.AUTOusará o GenerationType.TABLEque gera muitas consultas para a inserção.

Você pode evitar isso usando GenerationType.IDENTITY(se MySQL for o único banco de dados que você está usando) ou com estas notações (se você tiver vários bancos de dados):

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

sim, causa complicada para alguns erros de regressão desagradáveis ​​ao atualizar seu aplicativo Spring que também atualiza o Hibernate.
partindo de

1

Eu tentei de tudo, mas ainda não consegui fazer isso, estou usando mysql, jpa com hibernate, resolvi meu problema atribuindo o valor de id 0 no construtor A seguir está meu código de declaração de id

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

1

Como você definiu o id no tipo int na criação do banco de dados, você deve usar o mesmo tipo de dados na classe do modelo também. E como você definiu o id para incremento automático no banco de dados, você deve mencioná-lo na classe do modelo passando o valor 'GenerationType.AUTO' para o atributo 'estratégia' dentro da anotação @GeneratedValue. Em seguida, o código fica como abaixo.

@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

o mesmo que Pascal respondeu, apenas se você precisar usar .AUTO por algum motivo, você só precisa adicionar as propriedades do seu aplicativo:

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


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.