Todos nós conhecemos o comportamento padrão do Hibernate ao usar @SequenceGenerator
- aumenta a sequência real do banco de dados em um , multiplica este valor por 50 ( allocationSize
valor padrão ) - e então usa este valor como ID de entidade.
Este é um comportamento incorreto e conflita com a especificação que diz:
alocaçãoSize - (opcional) a quantidade a ser incrementada ao alocar números de sequência da sequência.
Para ser claro: não me preocupo com as lacunas entre os IDs gerados.
Preocupo-me com IDs que não são consistentes com a sequência de banco de dados subjacente. Por exemplo: qualquer outro aplicativo (que usa JDBC simples) pode querer inserir novas linhas sob os IDs obtidos na sequência - mas todos esses valores já podem ser usados pelo Hibernate! Loucura.
Alguém conhece alguma solução para este problema (sem configurar allocationSize=1
e assim degradar o desempenho)?
EDIT:
Para tornar as coisas claras. Se o último registro inserido tinha ID = 1
, então o HB usa valores 51, 52, 53...
para suas novas entidades MAS ao mesmo tempo: o valor da sequência no banco de dados será definido como 2
. O que pode facilmente levar a erros quando outros aplicativos estiverem usando essa sequência.
Por outro lado: a especificação diz (no meu entendimento) que a sequência do banco de dados deveria ter sido definida para 51
e, entretanto, o HB deve usar valores do intervalo 2, 3 ... 50
ATUALIZAÇÃO:
Como Steve Ebersole mencionou abaixo: o comportamento descrito por mim (e também o mais intuitivo para muitos) pode ser habilitado por configuração hibernate.id.new_generator_mappings=true
.
Obrigado a todos vocês.
ATUALIZAÇÃO 2:
Para futuros leitores, abaixo você pode encontrar um exemplo prático.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ")
@SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS")
private Long id;
}
persistence.xml
<persistence-unit name="testPU">
<properties>
<property name="hibernate.id.new_generator_mappings" value="true" />
</properties>
</persistence-unit>
save
precisa consultar o banco de dados para o próximo valor da sequência.SequenceGenerator
Hibernate irá consultar o banco de dados somente quando a quantidade de IDs especificados porallocationsize
acabar. Se você configurouallocationSize = 1
, esse é o motivo pelo qual o Hibernate consulta o banco de dados para cada inserção. Altere esse valor e pronto.hibernate.id.new_generator_mappings
configuração é muito importante. Eu espero que seja a configuração padrão que eu não tenha que gastar muito tempo pesquisando por que o número de id fica selvagem.Respostas:
Para ser absolutamente claro ... o que você descreve não está em conflito com as especificações de forma alguma. A especificação fala sobre os valores que o Hibernate atribui às suas entidades, não os valores realmente armazenados na seqüência do banco de dados.
No entanto, existe a opção de obter o comportamento que procura. Veja primeiro minha resposta em Existe uma maneira de escolher dinamicamente uma estratégia @GeneratedValue usando anotações JPA e Hibernate? Isso lhe dará o básico. Contanto que você esteja configurado para usar aquele SequenceStyleGenerator, o Hibernate interpretará
allocationSize
usando o "otimizador agrupado" no SequenceStyleGenerator. O "otimizador em pool" deve ser usado com bancos de dados que permitem uma opção de "incremento" na criação de sequências (nem todos os bancos de dados que suportam sequências suportam um incremento). De qualquer forma, leia sobre as várias estratégias de otimizador lá.fonte
org.hibernate.id.enhanced.SequenceStyleGenerator
. Você me surpreendeu.allocationSize=1
É uma microotimização antes de obter a consulta. O Hibernate tenta atribuir um valor na faixa de allocationSize e, portanto, tenta evitar a consulta ao banco de dados por sequência. Mas esta consulta será executada todas as vezes se você defini-la como 1. Isso dificilmente fará qualquer diferença, pois se seu banco de dados for acessado por algum outro aplicativo, ele criará problemas se o mesmo id for usado por outro aplicativo nesse meio tempo.A próxima geração de Sequence Id é baseada em alocação de tamanho.
Por padrão, é mantido como o
50
que é demais. Também só ajudará se você tiver quase50
registros em uma sessão que não sejam persistentes e que serão persistidos usando esta sessão e transação em particular.Portanto, você deve sempre usar
allocationSize=1
enquanto usaSequenceGenerator
. Como para a maioria dos bancos de dados subjacentes, a sequência é sempre incrementada por1
.fonte
allocationSize=1
Hibernate em cadasave
operação precisa fazer a viagem ao banco de dados para obter um novo valor de ID.allocationSize
e, portanto, tenta evitar a consulta ao banco de dados por sequência. Mas esta consulta será executada todas as vezes se você configurá-la para 1. Isso dificilmente fará qualquer diferença, pois se sua base de dados for acessada por algum outro aplicativo, ele criará problemas se o mesmo id for usado por outro aplicativo enquanto issoSteve Ebersole e outros membros,
Você poderia gentilmente explicar o motivo de uma id com um gap maior (por padrão 50)? Estou usando o Hibernate 4.2.15 e encontrei o seguinte código em org.hibernate.id.enhanced.OptimizerFactory cass.
Sempre que atinge o interior da instrução if, o valor hi está ficando muito maior. Portanto, meu id durante o teste com a reinicialização frequente do servidor gera os seguintes ids de sequência:
1, 2, 3, 4, 19, 250, 251, 252, 400, 550, 750, 751, 752, 850, 1100, 1150.
Eu sei que você já disse que não estava em conflito com a especificação, mas acredito que essa situação será muito inesperada para a maioria dos desenvolvedores.
A opinião de qualquer pessoa será muito útil.
Jihwan
ATUALIZAÇÃO: ne1410s: Obrigado pela edição.
cfrick: OK. Eu vou fazer isso. Foi meu primeiro post aqui e não sabia como usá-lo.
Agora, eu entendi melhor porque maxLo foi usado para dois propósitos: uma vez que o hibernate chama a sequência do banco de dados uma vez, continua a aumentar o id no nível do Java e salva no banco de dados, o valor do id do nível do Java deve considerar quanto foi alterado sem chamar a sequência DB quando chamar a sequência na próxima vez.
Por exemplo, a id de sequência era 1 em um ponto e hibernar inseriu 5, 6, 7, 8, 9 (com alocaçãoSize = 5). Da próxima vez, quando obtermos o próximo número de sequência, DB retornará 2, mas o hibernate precisa usar 10, 11, 12 ... Então, é por isso que "hi = lastSourceValue.copy (). MultiplyBy (maxLo + 1)" é usado para obter um próximo id 10 dos 2 retornados da sequência do banco de dados. Parece que o único problema foi durante a reinicialização frequente do servidor e este foi o meu problema com a lacuna maior.
Portanto, quando usamos o SEQUENCE ID, o id inserido na tabela não vai corresponder ao número da SEQUENCE no DB.
fonte
Depois de cavar no código-fonte do hibernate e a configuração abaixo vai para o banco de dados Oracle para o próximo valor após 50 inserções. Portanto, faça seu INST_PK_SEQ incrementar 50 cada vez que for chamado.
Hibernate 5 é usado para a estratégia abaixo
Verifique também abaixo http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence
fonte
allocationSize
neminitialValue
globalmente para todas as entidades (a menos que use apenas um gerador, mas IMHO não é muito legível).Eu também enfrentei esse problema no Hibernate 5:
Recebi um aviso como este abaixo:
Em seguida, alterei meu código para SequenceStyleGenerator:
Isso resolveu meus dois problemas:
fonte
Gostaria de verificar o DDL para a sequência no esquema. A implementação JPA é responsável apenas pela criação da sequência com o tamanho de alocação correto. Portanto, se o tamanho da alocação for 50, sua sequência deve ter o incremento de 50 em seu DDL.
Este caso pode ocorrer normalmente com a criação de uma sequência com tamanho de alocação 1 e posteriormente configurada para tamanho de alocação 50 (ou padrão), mas a sequência DDL não é atualizada.
fonte
ALTER SEQUENCE ... INCREMENTY BY 50;
não vai resolver nada, porque o problema continua o mesmo. O valor da sequência ainda não reflete os IDs de entidades reais.