Processamento em lote no JDBC
1. Introdução
O Java Database Connectivity (JDBC) é uma API Java usada para interagir com bancos de dados. O processamento em lote agrupa várias consultas em uma unidade e as passa em uma única viagem de rede para um banco de dados.
Neste artigo, vamos descobrir como JDBC pode ser usado para processamento em lote de consultas SQL.
Para obter mais informações sobre JDBC, você pode verificar nosso artigo de introduçãohere.
2. Por que processamento em lote?
Desempenho e consistência dos dados são os principais motivos para o processamento em lote.
2.1. Performance melhorada
Alguns casos de uso exigem que uma grande quantidade de dados seja inserida em uma tabela de banco de dados. Enquanto estiver usando o JDBC, uma das maneiras de conseguir isso sem processamento em lote é executar várias consultas sequencialmente.
Vejamos um exemplo de consultas sequenciais enviadas ao banco de dados:
statement.execute("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('1','EmployeeName1','Designation1')");
statement.execute("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('2','EmployeeName2','Designation2')");
Essas chamadas sequenciais aumentarão o número de viagens de rede ao banco de dados, resultando em um desempenho ruim.
Usando o processamento em lote, essas consultas podem ser enviadas ao banco de dados em uma chamada, melhorando o desempenho.
2.2. A consistência dos dados
Em certas circunstâncias, os dados precisam ser enviados para várias tabelas. Isso leva a uma transação inter-relacionada em que a sequência de consultas sendo enviadas é importante.
Quaisquer erros que ocorram durante a execução devem resultar em uma reversão dos dados enviados por consultas anteriores, se houver.
Vejamos um exemplo de adição de dados a várias tabelas:
statement.execute("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('1','EmployeeName1','Designation1')");
statement.execute("INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) "
+ "VALUES ('10','1','Address')");
Um problema típico na abordagem acima surge quando a primeira instrução é bem-sucedida e a segunda instrução falha. In this situation there is no rollback of the data inserted by the first statement, leading to data inconsistency.
Podemos alcançar a consistência dos dados estendendo uma transação em várias inserções / atualizações e, em seguida, consolidando a transação no final ou realizando uma reversão em caso de exceções, mas, neste caso, ainda estamos acessando o banco de dados repetidamente para cada instrução.
3. Como fazer processamento em lote
JDBC fornece duas classes,StatementePreparedStatement, para executar consultas no banco de dados. Ambas as classes têm sua própria implementação dos métodosaddBatch()eexecuteBatch(), que nos fornecem a funcionalidade de processamento em lote.
3.1. Processamento em lote usandoStatement
Com JDBC, a maneira mais simples de executar consultas em um banco de dados é por meio do objetoStatement.
Primeiro, usandoaddBatch(), podemos adicionar todas as consultas SQL a um lote e, em seguida, executar essas consultas SQL usandoexecuteBatch().
O tipo de retorno deexecuteBatch() é uma matrizint indicando quantos registros foram afetados pela execução de cada instrução SQL.
Vejamos um exemplo de criação e execução de um lote usando Declaração:
Statement statement = connection.createStatement();
statement.addBatch("INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES ('1','EmployeeName','Designation')");
statement.addBatch("INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) "
+ "VALUES ('10','1','Address')");
statement.executeBatch();
No exemplo acima, estamos tentando inserir registros nas tabelasEMPLOYEEeEMP_ADDRESS usandoStatement. Podemos ver como as consultas SQL estão sendo adicionadas no lote a ser executado.
3.2. Processamento em lote usandoPreparedStatement
PreparedStatement é outra classe usada para executar consultas SQL. Ela permite a reutilização de instruções SQL e exige que definamos novos parâmetros para cada atualização / inserção.
Vejamos um exemplo usandoPreparedStatement. Primeiro, configuramos a instrução usando uma consulta SQL codificada comoString:
String[] EMPLOYEES = new String[]{"Zuck","Mike","Larry","Musk","Steve"};
String[] DESIGNATIONS = new String[]{"CFO","CSO","CTO","CEO","CMO"};
String insertEmployeeSQL = "INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) "
+ "VALUES (?,?,?)";
PreparedStatement employeeStmt = connection.prepareStatement(insertEmployeeSQL);
Em seguida, percorremos uma matriz de valoresStringe adicionamos uma consulta recém-configurada ao lote.
Depois que o loop termina, executamos o lote:
for(int i = 0; i < EMPLOYEES.length; i++){
String employeeId = UUID.randomUUID().toString();
employeeStmt.setString(1,employeeId);
employeeStmt.setString(2,EMPLOYEES[i]);
employeeStmt.setString(3,DESIGNATIONS[i]);
employeeStmt.addBatch();
}
employeeStmt.executeBatch();
No exemplo mostrado acima, estamos inserindo registros na tabelaEMPLOYEE usandoPreparedStatement. Podemos ver como os valores a serem inseridos são definidos na consulta e, em seguida, adicionados ao lote a ser executado.
4. Conclusão
Neste artigo, vimos como o processamento em lote de consultas SQL é importante ao interagir com bancos de dados usando JDBC.
Como sempre, o código relacionado a este artigo pode ser encontradoover on Github.