Duvida básica (acho) no PreparedStatement

Meninos, acho que esta é básica.

Eu montei minha query de inserção no PreparedStatement :

sb.append(“insert into tabela …”);

depois executei a query de insercao :

stmt.execute();

Até ai tudo bem, só que já existe o Registro !!! e tá me mandando pra exception !!!

Tem Como testar isso antes ?

É recomendável este teste ou na Exception eu remonto minha query e dou update ?

Como vcs fazem ?

Obrigada

Giuliana

Tem muita gente que dá um select antes de dar um insert, mas eu não recomendaria isso justamente se houver mais de um programa ou uma thread acessando a mesma base - é que nem sempre você pode garantir que no intervalo de tempo entre dar o tal select para ver se o registro já existe e dar o insert (ou update) algum outro programa oi thread não vai fazer isso antes de você.

Por incrível que pareça, é melhor dar o insert, examinar a exceção (SQLException e ver se é alguma coisa do tipo “Chave duplicada”), e se for isso, dar o update.

Nó …

“examinar a exceção (SQLException e ver se é alguma coisa do tipo “Chave duplicada”)”

Cumé que faz isso ?!?!?!?

Desculpe a ignorancia

Giuliana

Giuliana, no seu exception vc fez um printStackTrace pra ver a mensagem de erro ?

Posta aí pra gente ver.

Edson.

a sim ae vai (não vou colar o printStack todo )

INFO: Server startup in 984 ms com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry '12030-1-M-2008-4' for key 1 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2985) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1631) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1723) at com.mysql.jdbc.Connection.execSQL(Connection.java:3256) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1313) at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:874)

Brigada

Giuliana

O código que vou passar varia de banco para banco. No caso do SQL Server, por exemplo, chave duplicada é o erro 3604; veja o código para o seu banco.

try {
    --- código para a inserção
...
} catch (SQLException ex) {
    if (ex.getErrorCode() == 3604) // Chave duplicada
        --- código para o update
}

http://support.microsoft.com/?scid=kb%3Ben-us%3B894562&x=7&y=14

NO caso do MySQL você pode tentar capturar essa exceção ( MySQLIntegrityConstraintViolationException ).

Giuliana, com relação a esta mensagem:

Realmente o que ocorre é que vc está inserindo um registro na tabela do banco de dados cuja unique key está sendo violada ( o valor já existe no banco ).

Nunca gostei muito de tratar por exceptions, mas fica a seu critério tentar qualquer uma das duas formas:

  1. o select antes do insert…, caso o registro retorne vc tenta o update, senão faz o insert deixando para tratar nas exceptions somente aquilo que for erro.

  2. Tratar no catch da exception.

Eu prefiro a primeira.

Att.
Edson.

Att.
Edson.

Pra quem usa Oracle, existe um comando chamado Merge,
que funciona da seguinte forma:

Você passa o comando, especifica qual a chave primária,
e passa os valores dos campos. Se já existir um registro
com aquela chave primária, o comando vai apenas fazer
update, com os valores que vc está passando.

Se não existir nenhum registro com aquela chave, ele faz o insert.

Uma mão na roda!!

Nó gente a opiniao de todos vcs foi mto proveitosa

Brigadona

Giuliana

Meninos, consegui capturar a exception assim :

MySQLIntegrityConstraintViolationException

Agora pintou um problema :

Este é um método que apenas gravo um registro, ele é chamado por outro método que está dentro de um comando WHILE e depois de mandar ele gravar o registro ele faz N processos dentro deste WHILE.

Uma vez lançada a exception ele retorna a classe chamadora deste método mas ele ESTÁ CONTINUANDO A FAZER OS PROCESSOS

Eu gostaria que ele, ao dar a EXCEPTION, parasse todos os processos e mostrasse pro usuário lá na minha JSP uma MENSAGEM DE REGISTRO DUPLICADO !

Poderiam quebrar mais este galho ?

Ficarei mto grata

Giuliana
:oops: :oops: :oops:

Thingol, eu tava refletindo sobre o que vc disse:

[quote=thingol]Tem muita gente que dá um select antes de dar um insert, mas eu não recomendaria isso justamente se houver mais de um programa ou uma thread acessando a mesma base - é que nem sempre você pode garantir que no intervalo de tempo entre dar o tal select para ver se o registro já existe e dar o insert (ou update) algum outro programa oi thread não vai fazer isso antes de você.

Por incrível que pareça, é melhor dar o insert, examinar a exceção (SQLException e ver se é alguma coisa do tipo “Chave duplicada”), e se for isso, dar o update. [/quote]

Cheguei a conclusão de que independente da forma a ser implementada teriamos problema, e que casos como esse que vc citou já começa a entrar no mérito de lock de transação, e para esse assunto tem dias de discussão que é quase dificil terminar. Penso que, independente de ter feito o teste com select (logo acima) ou tratado no catch exception, nada garante o estado do registro no banco… :expressionless: Precisaria de um delay bem grande entre o tratamento de catch e o insert (no caso dela), mas pode até ocorrer do registro ser excluído por outro usuário antes mesmo do update dela dentro do tratamento da chave duplicada. Aí seria até pior, pois quando ela tentou o insert o sistema disse que já existia, lançando a exception, e quando ele foi pro catch… outra transação removeu o registro, impossibilidando o update.

É um assuntos bem “chato”, mas geralmente dá “pano pra manga” em desenvolvimento.

Mas, acho que o meio termo (pra não dizer, o termo inteiro, ahuahuaha) seria utilizar algum framework de persistência que ajudasse a implementar isso, principalmente pelo fato de neste caso não haver mais a necessidade de se preocupar com código X ou Y de erros implementados diferentemente para cada tipo de banco de dados.

No mais, acho que se a Giuliana continuar com o sistema mais simples com JDBC puro mesmo, acho que ela podia pelo menos fazer um “SELECT FOR UPDATE” antes de deletar ou fazer update no registro, garantindo o lock sobre a tupla (isso é velho hein…).

Mas, vc tá usando Struts ou algo do tipo ? JSP + Servlets puro ?

Agora, independente disso, nessa situação vc vai precisar decidir o que vai querer fazer. No momento que vc trata a exception ela morre ali, a não ser que vc lance novamente:

throw new blablablaException();

Aí sim o método anterior conseguirá saber que “algo” aconteceu lá dentro.

Entenda melhor o conceito de relançar a exception. Agora, a forma que vc vai mostrar isso no sistema, pode ser configurado no struts com base na sua classe de excessão (caso esteja usando) ou então vc mesmo redireciona e mostra a mensagem através do seu servlet.

Att.
Edson.

Eu sou novata, utilizo JSP + SERVLET :oops:

Estou fazendo assim no meu méotdo de gravação :

	public String gravaFinanceiro(FinanceiroVO financeiro,Connection con) throws SQLException{
		sb = new StringBuffer();
		String retorno = "";
		try {
			sb.append("insert into financeiro (matFin,empFin,anoFin,mesFin,");
			sb.append("tipoFin,vlrFin) values (?,?,?,?,?,?)");
			stmt = con.prepareStatement(sb.toString());
			stmt.setInt(1,financeiro.getMatFin());
			stmt.setInt(2,financeiro.getEmpFin());
			stmt.setInt(3,financeiro.getAnoFin());
			stmt.setInt(4,financeiro.getMesFin());
			stmt.setString(5,financeiro.getTipoFin());
			stmt.setBigDecimal(6,financeiro.getVlrFin());
			stmt.execute();
			retorno = "Registro Salvo !";
		} catch (MySQLIntegrityConstraintViolationException e) {// Chave duplicada
			retorno = "Chave Duplicada";
		}finally{
			stmt.close();
			return retorno;
		}
	}

e na minha classe chamadora :

	While
.
.
.
.						try {
								financeiroBco.gravaFinanceiro(financeiro,con);
							} catch (MySQLIntegrityConstraintViolationException e) {
								// TODO: handle exception
							}
.
.
.
Mais métodos
Mais Métodos
.
.
.

lá embaixo um catch 

		}catch (Exception e) {
			// TODO: handle exception
		}finally{

Só que ele tá continuando a fazer os métodos …

O que estou fazendo de errado ?

Giuliana :cry: :cry:

Vc quer dizer que ele continua a executar os métodos da linha 13 e 14, é isso ?

Desculpe… 13 e 14 da classe chamadora.

Sim é isso !!! ele continua no While !

Coisa que não quero !!!

:cry:

Giuliana

Para mim, no método que grava ele lança e captura a exceção e passa para o método chamador que está na outra classe (Servlet), lá fiz o Try catch e pensava que ele iria propagar esta exceção e parar o processamento mas estou fazendo algo de errado e não estou sabendo …

:cry: :cry: :cry:

Giuliana

A sim, é pra já. Brigada

Coloquei mas ele volta para a classe chamadora e continua executando na meleca lá do While !!!

Gente, pode parecer que eu estou apenas tentando que vocês me ajudem sem eu pesquisar nem nada, mas eu estou pesquisando e inclusive lendo uma apostila que encontrei na NET sobre exceções. Eu realmente estou garrada nisso (propagação de Excecoes - acho que este é o termo certo !)

Mesmo assim mto obrigada

Giuliana :cry: