Problemas com concorrência

6 respostas
D

Olá pessoal,

Sou novo aqui e estou com um problema que não consigo resolver de jeito nenhum, por nunca ter esbarrado com algo assim.

Tenho um sistema web rodando em Tomcat 4 que está com um problema de concorrência:

Quando alguem gera um arquivo específico do sistema ele acessa o banco, pega o número atual da sequência, soma um a esse número e grava no banco. O cenário ideal é que cada arquivo gerado tenha um número único, mas não é isso que acontece. Quando muitos usuários acessam ao mesmo tempo alguns arquivos saem com o mesmo número.

Já tentei fazer desta classe que gera o arquivo (e também acessa e grava o número no banco) um singleton. Já tentei colocar synchronized no método. Nada disso adiantou. Fiz um jsp pra rodar num while grande em dois browsers e eles pegaram o mesmo número várias vezes.

Sei que não fui muito claro, mas alguém pode me ajudar ou pelo menos me apontar a algum lugar que fale sobre concorrência em sistemas web em Tomcat (ou J2EE em geral)? :cry:

Obrigado desde já!

6 Respostas

louds

Incremente a sequence toda vez que resolve.

select seq.next_val from dual

Se estiver usando “select max(xxx) +1” então você tem que dar um select for update nessa linha primeiro, e lembrar de dar commit depois de pegar o número.

D

Poderia fazer o commit, mas todo o método está dentro de uma transação. Se der algo errado no meio tenho q dar rollback.

Rubem_Azenha

Não da pra ter uma classe geradora de IDs?

ramilani12

Vc não poderia usar, um desbloqueio de objeto utilizando metodo wait() ?
enqunto aquele objeto nao for desbloqueado outro usuario nao consegue gerar o arquivo …

D

Não posso ter uma classe geradora de ids. O Id está em uma linha de uma tabela no banco. A linha tem valor inicial, valor máximo e valor atual. Quando a transação tem início o sistema vai ao banco, pega o valor atual, e dá um update acrescentando ele de 1. Não posso dar update logo depois de pegar o valor pois isto faz parte de uma transação (ou seja, se der algum problema tenho que dar rollback). Logo a única solução que eu vejo é fazer com que esse método não possa ser usado por dois usuários ao mesmo tempo.

Ao ramilani12, como eu implementaria isto? Vou mostrar mais ou menos como é:

O usuario entra num jsp que num determinado momento manda:

java.sql.Connection con = ConnectionPool.getConnection(); ObjTeste obj = new Obj(); obj.metodoGeraArquivo( con )
E lá na classe:

public synchronized int metodoGeraArquivo(Connection con) { con.setAutoCommit(false); (...) //esta classe é o entity bean que acessa a tabela e dá update logo depois TabelaNumero tbN = new TabelaNumero(); int retorno = tbN.getNumeroTabela(con); (...) return retorno; }
Já tentei transformar a classe ObjTeste em singleton e colocar synchronized no metodoGeraArquivo(). Já tentei transformar a classe TabelaNumero num singleton e colocar synchronized no getNumeroTabela().

Como eu colocaria um wait() e notify() aí? Ou outro tipo de semáforo (li sobre uma classe java.util.concurrent.Semaphore, mas tb não sei se funcionaria). Funcionaria mesmo rodando num servidor de aplicação web, como o Tomcat?

Tou ficando doido com isso. Desculpem qualquer ignorância :stuck_out_tongue:

louds

Você tem que usar os mecanismos corretos, senão vai ser sempre uma gambiarra a solução.

Usar 1 select e um 1 update não resolve se não for um “select for update” sua gambiarra vai funcionar somente até o ponto que precise ter 2 máquinas acessando e modificando essas tabelas.

Criado 30 de maio de 2006
Ultima resposta 31 de mai. de 2006
Respostas 6
Participantes 4