Re:Geração de número sequencial

Use as sequences que o banco oferece para gerar esses identificadores. Quanto a ano, a tua propria aplicação pode gerar um.

Quanto a gaps, usualmente sequences de bancos de dados costumam gerar gaps (veja a documentação do seu banco).
Se você precisa de algo que absolutamente não possa ter gaps normalmente é necessário ter uma tabela só para registrar o último número gerado.

Seu banco aceita stored procedures? Se aceitar, você pode escrever uma procedure que faça isso por você. Esse é o tipo de coisa que acho melhor que fique no banco.

[quote=wood]Bruno, com o thingol falou, as sequences geram gaps.

Thingol, segundo a idéia de criar outra tabela como seriam os passos?
Recuperar o último valor do banco;
Incrementá-lo na app;
Inserir a entidade desejada com o valor incrementado;
Atualizar tabela com o valor incrementado.

Seria isto?

E falando em um ambiente WEB, como ficaria a concorrência? Teria como eu garantir que nunca haveria um GAP?[/quote]

As sequences que estava me referindo são justamente essas mesmas tabelas que o thingol falou. Pelo menos no Oracle elas são conhecidas por este nome de sequence. Nelas chamamos uma operação nextval que fornece um valor, e o próprio banco cuida de incrementar o valor e tratar da concorrência.

Se você quer algo que é independente de banco de dados, então você precisa de algum código na sua aplicação. Basicamente você tem de abrir uma transação, incrementar o valor que está em uma determinada tabela (com um simples UPDATE você consegue fazer isso), obter esse valor e encerrar a transação.

Sim, voltaria ao problema dos gaps.

Sinceramente, você tem um grande problema nas mãos. Manter ZERO de gaps significa ter um controle excessivo de concorrência, o que geraria problema de performance por ter que executar um única operação por vez e garantir o sucesso dela.

Outra solução é acrescentar esse numero depois que a operação for completada. Diminuir(mas não eliminar) os problemas que podem dar antes de gerar o numero.

Eu sugiro que reveja a importância desse requisito.

E é por isso que o Oracle tem as sequences mas não garante que não haja gaps.
Como o Oracle é conhecido por ter excelente desempenho, ele tem de sacrificar certas coisas para garantir o desempenho.
Por exemplo, uma sequence normalmente não tem gaps, mas se você tentar criar muitos números sequenciais simultaneamente, ele começa a incluir alguns gaps.
O que ele garante é que não haja números sequenciais repetidos ou que eles comecem a “ir para trás”.

Eu sei que, se você não ficar desligando o banco a toda hora, o Oracle não apresenta gaps em sequencias. O que pode ocorrer é que, ao desligar o banco, e religá-lo novamente, as sequencias passem a contar de um valor um pouco maior que você está esperando.

Basta abrir uma transação (begin / commit). Enquanto a transação está em curso, os registros envolvidos na transação ficam “travados” (no caso do SQL Server) ou então uma outra coisa ocorre que garante a integridade (como é o caso do Oracle).

Cada banco tem sua maneira de travar tabelas.

Uma solução é o SELECT FOR UPDATE, que trava as linhas/cursores/registros, e é praticamente padrão entre varios bancos.

Usar um AtomicLong ou um AtomicIntegar não resolve o problema?
Basta cada vez que a aplicação iniciar buscar qual o ultimo numero sequencial gerado e iniciar o AtomicLong (ou AtomicInteger) com o número sequencial obtido.

Trabalhei em um sistema que precisei gerar um protocolo …

Para tratar possiveis problemas de concorrencia eu utilizei um select with table lock … resolveu perfeitamente …

Pessoal,

Estou enfrentado um problema e não estou conseguindo ver uma boa solução.
A aplicação terá que gerar um número sequencial, seguido pelo ano, e depois inserí-lo no banco de dados, de tal forma que não exista nenhum gap.

Ex.: 0001-2008, 0002-2008, …, 0001-2009

Alguém teria alguma dica para dar?
O projeto utiliza Struts, JDBC e EJB2.1

Bruno, com o thingol falou, as sequences geram gaps.

Thingol, segundo a idéia de criar outra tabela como seriam os passos?
Recuperar o último valor do banco;
Incrementá-lo na app;
Inserir a entidade desejada com o valor incrementado;
Atualizar tabela com o valor incrementado.

Seria isto?

E falando em um ambiente WEB, como ficaria a concorrência? Teria como eu garantir que nunca haveria um GAP?

Também acho, mas a política da empresa é ficar independente de BD.

[quote=Bruno Laturner]
As sequences que estava me referindo são justamente essas mesmas tabelas que o thingol falou. Pelo menos no Oracle elas são conhecidas por este nome de sequence. Nelas chamamos uma operação nextval que fornece um valor, e o próprio banco cuida de incrementar o valor e tratar da concorrência.[/quote]
Bruno, de qualquer forma isto ficaria na aplicação. Como é o tratamento em caso de Rollback? Acho que acabaria voltando para o mesmo problema, não?

Como formar uma fila de todas as trasações da tabela? (Depois que a transação é efetuada, é preciso mostrar o núméro para o cliente.)
Como dar um lock na tabela a partir da aplicação?

Será que estas idéias funcionam?

[quote=thingol][quote=wood]
Como dar um lock na tabela a partir da aplicação?
[/quote]

Basta abrir uma transação (begin / commit). Enquanto a transação está em curso, os registros envolvidos na transação ficam “travados” (no caso do SQL Server) ou então uma outra coisa ocorre que garante a integridade (como é o caso do Oracle).
[/quote]

O problema Thingol, é que eu quero garantir que enquanto eu estiver fazendo um insert ou update na tabela, não haverá mais ninguém atualizando-a.
Gerei um número 0001-2009 para a transação A, gerei o número 0002-2009 para a transação B.
A falhou, B inseriu. Gap.

Quando eu abro uma transação eu não estou dando um lock na tabela.