Como escrever em massa com transação e bulkInsert
Propósito. Inserir/atualizar muitas linhas com alta performance. Sem transação, cada INSERT vira um commit em disco (lento). Há três níveis: (1) envolver tudo em transaction(...), (2) reusar um SqliteStmt com reset(), (3) usar bulkInsert, que faz o loop bind/step/reset em código nativo (mais rápido).
APIs usadas
SqliteDb.transaction(Runnable body)— rodabodydentro deBEGIN/COMMIT; fazROLLBACKautomático sebodylançarRuntimeException(e relança). Forma recomendada para atomicidade.SqliteDb.begin()/commit()/rollback()— controle manual da transação (equivalem aexec("BEGIN"/"COMMIT"/"ROLLBACK")). Prefiratransaction(...)para não esquecer o rollback.SqliteDb.prepare(String sql)— prepara umSqliteStmtreusável (compila uma vez). Você deve fechá-lo (try-with-resources).SqliteStmt.bindInt/bindLong/bindDouble/bindString/bindBlob/bindNull(idx, v)ebindAll(Object...)— bind 1-based; retornamthis(fluente).step()executa;reset()prepara para a próxima execução (mantém os binds; useclearBindings()se quiser zerar).SqliteDb.bulkInsert(String sql, List<Object[]> rows)— preparasqluma vez e executa para cadaObject[]dentro de uma única transação, em loop nativo. Retorna o nº de linhas processadas. CadaObject[]tem um elemento por parâmetro?; tipos aceitos:Long/Integer,Double/Float,String,byte[],null. Os tipos de coluna são inferidos da PRIMEIRA linha — mantenha as linhas homogêneas. Aliases:bulkUpdate,bulkDelete.
Por que reusar o statement?
preparecompila o SQL; repetirpreparea cada linha recompila. Reusar comreset()compila uma vez e apenas re-binda — muito mais rápido em loops grandes.
Exemplo completo (copiar, colar e rodar)
package com.exemplo;
import java.util.*; // List, ArrayList
import dev.crossfly.ui.*; // Window
import dev.crossfly.ui.layout.*; // VerticalLayout
import dev.crossfly.sqlite.*; // SqliteDb, SqliteStmt
/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
try (SqliteDb db = SqliteDb.open("app.db"))
{
db.exec("CREATE TABLE IF NOT EXISTS t(a INTEGER, b TEXT)");
// Opção A — transação + statement reusado (reset entre execuções)
db.transaction(() ->
{
try (SqliteStmt st = db.prepare("INSERT INTO t(a, b) VALUES(?, ?)"))
{
for (int i = 0; i < 10_000; i++)
{
st.bindInt(1, i) // idx 1-based
.bindString(2, "row" + i)
.step();
st.reset(); // pronto para a próxima linha
}
}
}); // commit automático; rollback automático se lançar
// Opção B — bulkInsert nativo (o mais rápido para volumes grandes)
List<Object[]> rows = new ArrayList<>();
for (int i = 0; i < 10_000; i++)
rows.add(new Object[]{ i, "row" + i }); // tipos inferidos da 1ª linha
int n = db.bulkInsert("INSERT INTO t(a, b) VALUES(?, ?)", rows);
System.out.println(n + " linhas inseridas");
}
}
}
O trecho abaixo mostra só o miolo. Para rodar, coloque-o no esqueleto
MainWindowacima.
Trecho mínimo
// verificado na fonte: transaction, prepare + bind (1-based) + step + reset, bulkInsert
import dev.crossfly.sqlite.*;
import java.util.*;
try (SqliteDb db = SqliteDb.open("app.db"))
{
db.exec("CREATE TABLE IF NOT EXISTS t(a INTEGER, b TEXT)");
// Opção A — transação + statement reusado (reset entre execuções)
db.transaction(() ->
{
try (SqliteStmt st = db.prepare("INSERT INTO t(a, b) VALUES(?, ?)"))
{
for (int i = 0; i < 10_000; i++)
{
st.bindInt(1, i) // idx 1-based
.bindString(2, "row" + i)
.step();
st.reset(); // pronto para a próxima linha
}
}
}); // commit automático; rollback automático se lançar
// Opção B — bulkInsert nativo (o mais rápido para volumes grandes)
List<Object[]> rows = new ArrayList<>();
for (int i = 0; i < 10_000; i++)
rows.add(new Object[]{ i, "row" + i }); // tipos inferidos da 1ª linha
int n = db.bulkInsert("INSERT INTO t(a, b) VALUES(?, ?)", rows);
System.out.println(n + " linhas inseridas");
}
Aprofunde-se
- Trabalho em background · Performance e listas grandes
- Receitas irmãs: CRUD parametrizado · Uso fora da paint thread
Esta página foi útil?Obrigado pelo feedback!