[RESOLVIDO] (Hibernate/JPA) SEQUENCE - valor na entidade diferente do banco de dados

Necessito de ajuda urgente para resolver uma situação. Não consigo nem formular direito a pergunta:

Estou usando sequence no banco de dados e hibernate/jpa para popular o id de um objeto. Porém enquanto no banco de dados a sequence está em 70 e poucos, as entidades estão sendo persistidas com 3800 e poucos.

Altém tem idéia do porque disso?

Possuo a seguinte configuração:

classe CargoTerceirizado

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;


@Entity
@Table(name = "cargo_empregado_terc", schema = "cet")
public class CargoTerceirizado implements Serializable {
(...)
	
	@Id
	@Column(name = "num_seq_caet")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CARGO_SEQ")
	@SequenceGenerator(name = "CARGO_SEQ", sequenceName = "cet.num_seq_caet")
	private Integer id;
(...)

persistence.xml


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

	<persistence-unit name="CET_JTA" transaction-type="JTA">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<jta-data-source>java:CET_DB_DS</jta-data-source>
(...)
		<class>com.cet.entidades.CargoTerceirizado</class>
(...)
			<property name="hibernate.archive.autodetection" value="class" />
			<property name="hibernate.format_sql" value="true" />
			<property name="use_sql_comments" value="true" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
			<property name="hibernate.cache.use_second_level_cache" value="false"/>
		</properties>

	</persistence-unit>

</persistence>

Executo o seguinte método:

	public Integer inserir(CargoTerceirizado cargo) throws DAOException {
		//Exibe informações sobre o valor atual da sequence		
		Object object = 
			getEntityManager().createNativeQuery("select nextval ('cet.num_seq_caet')").getSingleResult();
		System.out.println(object);
		System.out.println(object.getClass().getName());

		//executa a inserção
		getEntityManager().persist(cargo);
		getEntityManager().flush();		
		return cargo.getId();
	}

Recebo o como log:


17:19:58,584 DEBUG [org.hibernate.SQL] 
    select
        nextval ('cet.num_seq_caet')
17:19:58,584 TRACE [org.hibernate.type.BigIntegerType] returning '75' as column: nextval
17:19:58,584 INFO  [STDOUT] 75
17:19:58,584 INFO  [STDOUT] java.math.BigInteger
17:19:58,584 DEBUG [org.hibernate.SQL] 
    select
        nextval ('cet.num_seq_caet')
17:19:58,896 DEBUG [org.hibernate.SQL] 
    insert 
    into
        cet.cargo_empregado_terc
        (desc_caet, num_seq_caet) 
    values
        (?, ?)
17:19:58,912 TRACE [org.hibernate.type.StringType] binding 'aaaaaaaa' to parameter: 1
17:19:58,912 TRACE [org.hibernate.type.IntegerType] binding '3800' to parameter: 2
17:19:59,052 DEBUG [com.cet.apresentacao.CargoBean] Persist id=3800

(...)

17:20:11,365 DEBUG [org.hibernate.SQL] 
    select
        nextval ('cet.num_seq_caet')
17:20:11,381 TRACE [org.hibernate.type.BigIntegerType] returning '77' as column: nextval
17:20:11,381 INFO  [STDOUT] 77
17:20:11,381 INFO  [STDOUT] java.math.BigInteger
17:20:11,381 DEBUG [org.hibernate.SQL] 
    insert 
    into
        cet.cargo_empregado_terc
        (desc_caet, num_seq_caet) 
    values
        (?, ?)
17:20:11,381 TRACE [org.hibernate.type.StringType] binding 'bbbbbbbbbbb' to parameter: 1
17:20:11,381 TRACE [org.hibernate.type.IntegerType] binding '3801' to parameter: 2
17:20:11,396 DEBUG [com.cet.apresentacao.CargoBean] Persist id=3801

(...)

17:24:30,318 DEBUG [org.hibernate.SQL] 
    select
        nextval ('cet.num_seq_caet')
17:24:30,318 TRACE [org.hibernate.type.BigIntegerType] returning '78' as column: nextval
17:24:30,334 INFO  [STDOUT] 78
17:24:30,334 INFO  [STDOUT] java.math.BigInteger
17:24:30,334 DEBUG [org.hibernate.SQL] 
    insert 
    into
        cet.cargo_empregado_terc
        (desc_caet, num_seq_caet) 
    values
        (?, ?)
17:24:30,334 TRACE [org.hibernate.type.StringType] binding 'ccccccccccccc' to parameter: 1
17:24:30,334 TRACE [org.hibernate.type.IntegerType] binding '3802' to parameter: 2
17:24:30,334 DEBUG [com.cet.apresentacao.CargoBean] Persist id=3802

[list]O primeiro nextval é efetuado para o sysout. Ele retorna 75.[/list]
[list]Ao persistir a entidade, o valor atribuido ao campo é 3800 (deveria ser 76 retornado pelo nextval executado pelo hibernate)[/list]
[list]O nextval seguinte, é consumido pelo sysout e retorna 77. (sim, o hibernate executou o nextval que retornou 76 ao persistir a entidade ‘aaaaaaaaaaa’)[/list]
[list]O nextval seguinte, retorna 77 e é consumido pelo sysout.[/list]
[list]O hibernate persiste a entidade sem efetuar no nextval atribuíndo 3801.[/list]
[list]O nextval seguinte retorna 78. (O hibernate persistiu a entidade ‘bbbbbbbbbbbb’ sem executar nextval)[/list]
[list]O hibernate persiste a entidade ‘cccccccccccc’ atribuindo 3802.[/list]

Em quatro anos de java nunca vi isso.
Todas as entidades do sistema estão passando pelo mesmo problema.
Há entidades em que a sequência reflete um registro que será cadastrado em um sistema mainframe que necessita respeitar um range. Não tenho controle nenhum sobre os ids se a sequence está na casa dos 70 e o id fica na casa dos 3800.

Preciso de ajuda urgente.

Grato
Pedro Vaz.

Sei que não é o ideal, mas na hora do desespero…

Up!

Estou utilizando a versão do jboss 4.2.1 que vem com hibernate-3.2, hibernate-entitymanager-3.2.1.GA e hibernate-annotations-3.2.1.GA.

O método org.hibernate.id.BinderHelper.makeIdGenerator(…) é responsável por setar o atributo identifierGeneratorProperties que determina o valor do atributo maxLo da classe org.hibernate.id.SequenceHiLoGenerator responsável pela geração do id da classe.

Segundo a especificação da classe SequenceGenerator ( http://java.sun.com/javaee/5/docs/api/javax/persistence/SequenceGenerator.html#allocationSize() ), o valor default de allocationSize é 50.

Se o annotation respnsável pelo mapeamento da sequence (@SequenceGenerator(name = “CARGO_SEQ”, sequenceName = “cet.num_seq_caet”)) não possui o atributo allocationSize, a classe SequenceHiLoGenerator assume o valor 49 para o atributo maxLo.

A geração do id é efetuado pelo método da classe org.hibernate.id.SequenceHiLoGenerator:


	public synchronized Serializable generate(SessionImplementor session, Object obj) 
	throws HibernateException {
		if (maxLo < 1) {
			//keep the behavior consistent even for boundary usages
			long val = ( (Number) super.generate(session, obj) ).longValue();
			if (val == 0) val = ( (Number) super.generate(session, obj) ).longValue();
			return IdentifierGeneratorFactory.createNumber( val, returnClass );
		}
		if ( lo>maxLo ) {
			long hival = ( (Number) super.generate(session, obj) ).longValue();
			lo = (hival == 0) ? 1 : 0;
			hi = hival * ( maxLo+1 );
			if ( log.isDebugEnabled() )
				log.debug("new hi value: " + hival);
		}

		return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass );
	}

}

Ou seja, se allocationSize não é informado, o valor retornado pela primeira consulta é hi = 50 vezes o valor da sequence no banco. As próximas 49 inserções não chamarão a sequence do banco, mas sim incrementarão o valor de lo e somarão ao valor de hi.

A solução para o problema é setar o atributo opcional allocationSize = 0.

@SequenceGenerator(name = "CARGO_SEQ", sequenceName = "cet.num_seq_caet", allocationSize = 0)

Eu sou muito foda!

Brocou!

Vlw.