- I would like to see an example of an appropriate treatment for this exception in this case.
It depends a lot on the type of system.
If it is desktop, you can show a dialog box with the error message. If it is web, you can return the page to the user with the error message in some part of HTML.
The important thing when dealing with an exception is that the behavior of the system is consistent, that it does not fall into a worse error yet and does not hide the user’s mistakes.
How to display error messages should not be the responsibility of database access classes (Data Access Objects, for example), so one way to perform a proper treatment is to encapsulate the database exceptions in a generic database exception and treat this other exception in control classes (Controllers).
For example:
public void update(Pessoa pessoa) throws DataBaseException {
Connection conexao = getConexao();
try {
PreparedStatement preparedStatement = conexao.prepareStatement(sqlUpdate);
preparedStatement.setString(1, pessoa.getNome());
preparedStatement.setString(2, pessoa.getCpf());
preparedStatement.setInt(3, pessoa.getIdPessoa());
preparedStatement.execute();
preparedStatement.close();
conexao.close();
} catch (Exception e) {
logger.error(e);
throw new DataBaseException("Erro ao atualizar a pessoa!", e);
} finally {
if (conexao != null) {
try {
conexao.close();
} catch (SQLException e) {
logger.error(e);
}
}
}
}
The above method saves the original error in a log using its own API, as "printing" errors for the output is not a good practice.
In addition, it encapsulates any exception in a custom exception DataBaseException
. This exception would be used in all database access routines.
Another detail is that a block is required finally
to close the connection, otherwise an error would result in leakage of connections, i.e., multiple open and unopened connections. That’s a big headache in poorly planned systems. The server starts crashing after some time of use and it will take someone to figure out the problem.
The second catch
does not need treatment beyond the log because it just tries to close the connection. If this fails the problem is lower and there is not much to do.
In general, it is "ugly" to capture a generic exception like Exception
. But there is a reason for this. There are cases, such as the developer putting an extra parameter in the PreparedStatement
, where an error other than SQLException
. And there’s a rule of the business world: does not show technical error to the user.
Miss a mistake like NullPointerException
or StringIndexOutOfBroundsException
to the screen is worse than showing a generic error. The message "unexpected error occurred, contact support" is sometimes the most useful thing for the user who knows nothing about technology.
Error cases where the user can actually act can be dealt with specifically. For example, if the user tries to delete a record that is a foreign key from another table, then it is possible to display a specific message that it is necessary to delete the data from the other table before deleting the current record.
You can make a more sophisticated mechanism than just putting catch
with Exception
, but I will leave it at that for example. This mechanism could consist of a global treatment routine that showed the user different messages for each type of exception.
Let’s imagine now a method that treats the user action to update the data from Pessoa
.
If it were a desktop system:
public void doCliqueBotarAtualizarAction() {
Pessoa pessoa = recuperarPessoaDosCamposDaTela();
try {
pessoaDAO.update(pessoa);
mostrarDialogoSucesso("Dados alterados com sucesso!");
} catch (DataBaseException e) {
mostrarDialogoErro(e.getMessage());
}
}
The above method simply shows a success or failure box depending on the case.
If it were a web system with Spring MVC, for example:
@RequestMapping(value="/atualizaPessoa", method=RequestMethod.POST)
public ModelAndView atualizarPessoa(Pessoa pessoa) {
try {
pessoaDAO.update(pessoa);
return new ModelAndView("tela-pesquisa")
.addObject("mensagem", "Dados alterados com sucesso!");
} catch (DataBaseException e) {
return new ModelAndView("tela-edicao")
.addObject("pessoa", pessoa)
.addObject("mensagemErro", e.getMessage());
}
}
The above method receives a request POST
to update the person. If successful the user is directed to the search screen with the success message. If failure occurs, the user is directed to the edit screen showing the person and also the error message.
Another approach would be to treat separately SQLException
of another kind of Exception
, but it must be examined whether in practice it will make any difference, because replicating the error treatment to do the same thing would simply not make sense.
- By manipulating this checked Exception, storing Stracktrace in a Log and showing a warning to the user that something that could not be done to update the data, it would be considered that the exception has been handled?
Yes, since it ensures that the system will not be in an inconsistent state.
Showing the message is enough if there are no unwanted side effects.
For cases, for example, there are changed several tables, it is important to place the changes in a transaction and do the rollback in case of failure.
Take an example:
public void transferencia(Conta fonte, Conta destino, BigDecimal valor) throws BusinessException {
boolean sucesso = false;
iniciarTransacao();
try {
contaDao.debitar(fonte, valor);
contaDao.creditar(destino, valor);
sucesso = true;
} catch (Exception e) {
logger.error(e);
throw new BusinessException("Não foi possível efetuar a transferência!", e);
} finally {
if (sucesso) efetuarTransacao();
else desfazerTransacao();
}
}
- And if the above topic were added to clear the fields for filling in personal data and return to the initial data change screen for the user to try editing again, it would be considered that the exception was treated?
Wiping the data is usually not a good idea, after all it is too much work and headache for the user.
Showing the fields with problem is a better task if it is the case. For this it is important to validate the fields before to try to execute the query in the database.
In general, the constraints of the database as Unic or not null should be used to ensure the integrity of the bank, but for user input validation they should be the last resource.
And if the SQL error, as an incorrect syntax, will not help the user to try again, it is probably a system bug.
Considerations
The level of detail of error handling varies greatly from case to case.
It is best to code "securely" by validating all entries, creating unit tests to validate your queries and thus minimize any possibility of an SQL error.
I shouldn’t put wiki. Is there a special reason for this? I have only one criticism of these codes. Not that it is wrong, it even makes sense. They capture any exception and launch another more specific does not please me. I say it makes sense because the new exception says it was not possible to perform the operation in specifying what occurred or how to help resolve. And it’s true, but it doesn’t help at all.
– Maniero
Maybe he put as wiki without realizing? Tb did not understand why it is wiki
– Math
@Math is, that’s it, I’m glad he can reverse :)
– Maniero
@bigown The wiki was totally unintentionally. Which to the treatment of exceptions, I understand the problem and I appreciate the remark. I do not know if it solves, but I added some comments and remarks in the reply .
– utluiz
@utluiz yes, important points were placed. It is clearer that the solution is not definitive, is a basic example to start.
– Maniero