Olá!
Neste artigo, falarei brevemente sobre o processamento em lote de instruções SQL (DML): INSERT, UPDATE, DELETE, como uma das maneiras de obter maior desempenho.

Benefícios
Diferentemente da execução sequencial de cada consulta SQL, o processamento em lote possibilita o envio de um conjunto inteiro de consultas (pacote) em uma chamada, reduzindo o número de conexões de rede necessárias e permitindo que o banco de dados execute um certo número de consultas em paralelo, o que pode aumentar significativamente a velocidade de execução. Imediatamente, faça uma reserva para observar um efeito notável ao inserir, atualizar ou excluir grandes quantidades de dados em uma tabela do banco de dados.
Tabela de banco de dados
Como exemplo, usaremos a tabela de livros com os campos id e title.
1. JDBC - processamento em lote
Antes de passar para exemplos de implementação, é necessário destacar vários pontos importantes:
- JDBC , supportsBatchUpdates() DatabaseMetaData, , . true, .
- , setAutoCommit(false). , commit() rollback(). rollback() SQL .
- — , JDBC Statement, PreparedStatement CallableStatement, .
, Statement, PreparedStatement CallableStatement . , BATCH_SIZE. , . , , Hibernate 10 50.
, SQL INSERT. UPDATE, DELETE .
1.1. Statement
Statement book.
connection.setAutoCommit(false);
try (Statement stmt = connection.createStatement()) {
for (int i = 1; i <= SIZE; i++) {
stmt.addBatch("INSERT INTO book (title) VALUES ('" + "JDBC Insert Example: " + i + "')");
if (i % BATCH_SIZE == 0 || i == SIZE) {
try {
int[] result = stmt.executeBatch();
connection.commit();
} catch (BatchUpdateException ex) {
Log(ex);
connection.rollback();
}
}
}
}
:- C Statement;
- C void addBatch( String SQL );
- executeBatch(). executeBatch() .
Statement SQL INSERT, UPDATE, DELETE.
SQL , .
1.2. PreparedStatement
PreparedStatement book.
connection.setAutoCommit(false);
try (PreparedStatement pstmt = connection.prepareStatement("INSERT INTO book (title) VALUES (?)")) {
for (int i = 1; i <= SIZE; i++) {
pstmt.setString(1, "JDBC Insert Example: " + i);
pstmt.addBatch();
if (i % BATCH_SIZE == 0 || i == SIZE) {
try {
int[] result = pstmt.executeBatch();
connection.commit();
} catch (BatchUpdateException ex) {
Log(ex);
connection.rollback();
}
}
}
}
:- C PreparedStatement SQL ;
- , ;
- void addBatch();
- executeBatch().
3) 4) , Statement, — addBatch() .
SQL , , . , .
PreparedStatement SQL (INSERT, UPDATE, DELETE) Statement, - .
1.3. CallableStatement
CallableStatement .
, OUT INOUT.
CallableStatement book.
connection.setAutoCommit(false);
try (CallableStatement cstmt = connection.prepareCall("call insert_book(?)")) {
for (int i = 1; i <= SIZE; i++) {
cstmt.setString(1, "JDBC Insert Example: " + i);
cstmt.addBatch();
if (i % BATCH_SIZE == 0 || i == SIZE) {
try {
int[] result = cstmt.executeBatch();
connection.commit();
} catch (BatchUpdateException ex) {
Log(ex);
connection.rollback();
}
}
}
}
:- C CallableStatement ;
- , ;
- void addBatch();
- executeBatch().
, PreparedStatement.
, , .
- , .
CallableStatement , - .
1.4. BatchUpdateException
BatchUpdateException, . BatchUpdateException , SQL , - , ResultSet. BatchUpdateException ( getUpdateCounts()), , executeBatch. , SQL . , c (Statement.EXECUTE_FAILED) .
:
...
} catch (BatchUpdateException ex) {
int[] updateCount = ex.getUpdateCounts();
int count = 1;
for (int i : updateCount) {
if (i == Statement.EXECUTE_FAILED) {
System.out.println("Request " + count + ": Execute failed");
} else {
System.out.println("Request " + count + ": OK");
}
count++;
}
}
...
. , , , , . BatchUpdateException SQL , . .
2. Hibernate —
2.1.
, , hibernate.jdbc.batch_size Hibernate.cfg.xml . Hibernate SQL INSERT, UPDATE, DELETE JDBC . SQL JDBC hibernate.order_inserts, hibernate.order_updates true, Hibernate SQL . SQL , JDBC Hibernate addBatch() PreparedStatement, SQL .
Hibernate.cfg.xml
...
<property name="hibernate.jdbc.batch_size">50</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
...
2.2.
. , . , Hibernate , OutOfMemoryException. 2 :
- flush() clear() .
:
try (Session session = HibernateUtil.getSessionFactory().getCurrentSession()) {
Transaction transaction = session.getTransaction();
transaction.begin();
for (int i = 1; i <= SIZE; i++) {
session.persist(new Book("Hibernate Insert Example: " + i));
if (i % BATCH_SIZE == 0) {
session.flush();
session.clear();
}
}
transaction.commit();
}
- StatelessSession. StatelessSession . , , , (aliasing) . , Hibernate. Hibernate.
:
try (StatelessSession session = HibernateUtil.getSessionFactory().openStatelessSession()) {
Transaction transaction = session.getTransaction();
transaction.begin();
for (int i = 1; i <= SIZE; i++) {
session.persist(new Book("Hibernate Insert Example: " + i));
}
transaction.commit();
}
A execução em lote de consultas SQL é uma das maneiras conhecidas de melhorar o desempenho em que você deve prestar atenção. Reduzir o número de conexões de rede ao banco de dados e aumentar a velocidade de execução da consulta é uma vantagem significativa a favor do uso do processamento em lote.
Exemplos de código podem ser encontrados no GitHub .