INSERT en Java
Insertar datos en MySQL desde Java se realiza con PreparedStatement y su metodo executeUpdate(). Si quieres repasar la sintaxis SQL del INSERT, consulta la guía de INSERT en MySQL. JDBC ofrece soporte nativo para recuperar claves generadas automaticamente, insertar por lotes con addBatch()/executeBatch() y manejar transacciones para garantizar la integridad de inserciones multiples. En este articulo aprenderas todas las tecnicas de insercion disponibles en Java.
Requisitos previos
Necesitas una conexion JDBC configurada y la tabla productos creada. Si no la tienes, consulta los articulos anteriores.
Codigo completo
Este ejemplo inserta un producto y recupera el ID generado automaticamente:
import java.sql.*;
public class InsertMySQL {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/tienda?useSSL=false&serverTimezone=UTC";
try (Connection conn = DriverManager.getConnection(url, "root", "tu_contraseña")) {
String sql = "INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setString(1, "Tablet Samsung Galaxy Tab S9");
pstmt.setString(2, "Tablets");
pstmt.setDouble(3, 8999.00);
pstmt.setInt(4, 35);
int filasAfectadas = pstmt.executeUpdate();
try (ResultSet keys = pstmt.getGeneratedKeys()) {
if (keys.next()) {
long nuevoId = keys.getLong(1);
System.out.println("Producto insertado exitosamente");
System.out.println("ID generado: " + nuevoId);
System.out.println("Filas afectadas: " + filasAfectadas);
}
}
}
} catch (SQLException e) {
System.err.println("Error: " + e.getMessage());
}
}
}Salida esperada:
Producto insertado exitosamente
ID generado: 7
Filas afectadas: 1
Explicacion paso a paso
El metodo executeUpdate() ejecuta sentencias INSERT, UPDATE o DELETE y devuelve el numero de filas afectadas. Para recuperar el ID auto-generado, debes pasar Statement.RETURN_GENERATED_KEYS como segundo argumento de prepareStatement(). Luego llamas a getGeneratedKeys() que devuelve un ResultSet con las claves generadas.
Los metodos setXxx() asignan valores a los placeholders ? en la sentencia SQL. Cada metodo corresponde a un tipo Java: setString() para VARCHAR, setInt() para INT, setDouble() para DECIMAL/DOUBLE, setBigDecimal() para DECIMAL de alta precision, setTimestamp() para DATETIME, entre otros.
Insertar con variables
public static long insertarProducto(Connection conn, String nombre, String categoria,
double precio, int stock) throws SQLException {
String sql = "INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setString(1, nombre);
pstmt.setString(2, categoria);
pstmt.setDouble(3, precio);
pstmt.setInt(4, stock);
pstmt.executeUpdate();
try (ResultSet keys = pstmt.getGeneratedKeys()) {
if (keys.next()) {
return keys.getLong(1);
}
}
}
return -1;
}
// Uso
long id = insertarProducto(conn, "Cargador USB-C 65W", "Accesorios", 599.00, 300);
System.out.println("Producto creado con ID: " + id);Insertar con tipos especiales
Cuando trabajas con fechas, valores NULL o tipos decimales de alta precision, necesitas metodos especificos:
String sql = "INSERT INTO pedidos (cliente_id, fecha, estado, total, notas) VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setInt(1, 1);
pstmt.setTimestamp(2, Timestamp.valueOf(java.time.LocalDateTime.now()));
pstmt.setString(3, "pendiente");
pstmt.setBigDecimal(4, new java.math.BigDecimal("16197.99"));
pstmt.setNull(5, Types.VARCHAR); // Valor NULL explicito
pstmt.executeUpdate();
}Insercion por lotes con addBatch/executeBatch
Cuando necesitas insertar muchos registros, la insercion por lotes es significativamente mas rapida que ejecutar cada INSERT individualmente. El metodo addBatch() acumula las sentencias y executeBatch() las envia todas al servidor en una sola operacion de red:
public static int insertarLote(Connection conn) throws SQLException {
String sql = "INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)";
Object[][] productos = {
{"Impresora HP LaserJet", "Impresoras", 3499.00, 20},
{"Cable HDMI 2.1 3m", "Accesorios", 349.00, 500},
{"Mousepad XXL Gaming", "Accesorios", 449.00, 200},
{"Soporte Monitor Ajustable", "Accesorios", 1299.00, 75},
{"Adaptador DisplayPort", "Accesorios", 249.00, 400},
};
conn.setAutoCommit(false);
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (Object[] producto : productos) {
pstmt.setString(1, (String) producto[0]);
pstmt.setString(2, (String) producto[1]);
pstmt.setDouble(3, (Double) producto[2]);
pstmt.setInt(4, (Integer) producto[3]);
pstmt.addBatch();
}
int[] resultados = pstmt.executeBatch();
conn.commit();
int totalInsertados = 0;
for (int r : resultados) {
if (r >= 0) totalInsertados += r;
}
System.out.println("Registros insertados: " + totalInsertados);
return totalInsertados;
} catch (SQLException e) {
conn.rollback();
throw e;
} finally {
conn.setAutoCommit(true);
}
}Salida esperada:
Registros insertados: 5
El metodo executeBatch() devuelve un array de enteros donde cada posicion indica el resultado de cada sentencia del lote. Un valor positivo indica el numero de filas afectadas, Statement.SUCCESS_NO_INFO (-2) indica exito sin informacion de filas, y Statement.EXECUTE_FAILED (-3) indica un fallo.
INSERT ON DUPLICATE KEY UPDATE
Cuando quieres insertar un registro o actualizarlo si ya existe (basado en una clave unica), puedes usar INSERT ... ON DUPLICATE KEY UPDATE:
public static void insertarOActualizar(Connection conn, String nombre, String categoria,
double precio, int stock) throws SQLException {
String sql = "INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?) "
+ "ON DUPLICATE KEY UPDATE precio = VALUES(precio), stock = stock + VALUES(stock)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, nombre);
pstmt.setString(2, categoria);
pstmt.setDouble(3, precio);
pstmt.setInt(4, stock);
int resultado = pstmt.executeUpdate();
// resultado = 1 si se inserto, 2 si se actualizo
if (resultado == 1) {
System.out.println("Producto insertado: " + nombre);
} else if (resultado == 2) {
System.out.println("Producto actualizado: " + nombre);
}
}
}Caso practico
Veamos un sistema de registro de pedidos completo que inserta en multiples tablas dentro de una transaccion:
import java.sql.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
public class RegistroPedidos {
public static long registrarPedido(Connection conn, int clienteId,
List<Map<String, Object>> items) throws SQLException {
conn.setAutoCommit(false);
try {
// Calcular total
BigDecimal total = BigDecimal.ZERO;
for (Map<String, Object> item : items) {
BigDecimal cantidad = BigDecimal.valueOf((Integer) item.get("cantidad"));
BigDecimal precioUnitario = (BigDecimal) item.get("precioUnitario");
total = total.add(cantidad.multiply(precioUnitario));
}
// Insertar pedido
String sqlPedido = "INSERT INTO pedidos (cliente_id, fecha, estado, total) VALUES (?, NOW(), ?, ?)";
long pedidoId;
try (PreparedStatement pstmt = conn.prepareStatement(sqlPedido, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setInt(1, clienteId);
pstmt.setString(2, "pendiente");
pstmt.setBigDecimal(3, total);
pstmt.executeUpdate();
try (ResultSet keys = pstmt.getGeneratedKeys()) {
keys.next();
pedidoId = keys.getLong(1);
}
}
// Insertar detalles y descontar stock
String sqlDetalle = "INSERT INTO detalle_pedido (pedido_id, producto_id, cantidad, precio_unitario) "
+ "VALUES (?, ?, ?, ?)";
String sqlStock = "UPDATE productos SET stock = stock - ? WHERE id = ? AND stock >= ?";
try (PreparedStatement pstmtDetalle = conn.prepareStatement(sqlDetalle);
PreparedStatement pstmtStock = conn.prepareStatement(sqlStock)) {
for (Map<String, Object> item : items) {
int productoId = (Integer) item.get("productoId");
int cantidad = (Integer) item.get("cantidad");
BigDecimal precioUnitario = (BigDecimal) item.get("precioUnitario");
// Insertar detalle
pstmtDetalle.setLong(1, pedidoId);
pstmtDetalle.setInt(2, productoId);
pstmtDetalle.setInt(3, cantidad);
pstmtDetalle.setBigDecimal(4, precioUnitario);
pstmtDetalle.executeUpdate();
// Descontar stock
pstmtStock.setInt(1, cantidad);
pstmtStock.setInt(2, productoId);
pstmtStock.setInt(3, cantidad);
int actualizado = pstmtStock.executeUpdate();
if (actualizado == 0) {
throw new SQLException("Stock insuficiente para producto " + productoId);
}
}
}
conn.commit();
System.out.println("Pedido #" + pedidoId + " registrado exitosamente");
System.out.println(" Cliente: " + clienteId);
System.out.println(" Items: " + items.size());
System.out.printf(" Total: $%s%n", total);
return pedidoId;
} catch (SQLException e) {
conn.rollback();
throw e;
} finally {
conn.setAutoCommit(true);
}
}
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/tienda?useSSL=false&serverTimezone=UTC";
try (Connection conn = DriverManager.getConnection(url, "root", "tu_contraseña")) {
List<Map<String, Object>> items = List.of(
Map.of("productoId", 1, "cantidad", 1, "precioUnitario", new BigDecimal("12999.99")),
Map.of("productoId", 2, "cantidad", 2, "precioUnitario", new BigDecimal("1599.00"))
);
registrarPedido(conn, 1, items);
} catch (SQLException e) {
System.err.println("Error al registrar pedido: " + e.getMessage());
}
}
}Salida esperada:
Pedido #1 registrado exitosamente
Cliente: 1
Items: 2
Total: $16197.99
Manejo de errores
Los errores comunes al insertar datos y como identificarlos:
public static Map<String, Object> insertarSeguro(Connection conn, String nombre, String categoria,
double precio, int stock) {
String sql = "INSERT INTO productos (nombre, categoria, precio, stock) VALUES (?, ?, ?, ?)";
Map<String, Object> resultado = new java.util.HashMap<>();
try (PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setString(1, nombre);
pstmt.setString(2, categoria);
pstmt.setDouble(3, precio);
pstmt.setInt(4, stock);
pstmt.executeUpdate();
try (ResultSet keys = pstmt.getGeneratedKeys()) {
if (keys.next()) {
resultado.put("exito", true);
resultado.put("id", keys.getLong(1));
}
}
} catch (SQLException e) {
resultado.put("exito", false);
switch (e.getErrorCode()) {
case 1062:
resultado.put("mensaje", "Ya existe un producto con ese nombre");
break;
case 1048:
resultado.put("mensaje", "Faltan campos obligatorios (valor NULL no permitido)");
break;
case 1406:
resultado.put("mensaje", "Uno de los valores excede la longitud permitida");
break;
case 1452:
resultado.put("mensaje", "Referencia a tabla externa no valida (clave foranea)");
break;
default:
resultado.put("mensaje", "Error [" + e.getErrorCode() + "]: " + e.getMessage());
}
}
return resultado;
}Ahora que sabes como insertar datos, en el siguiente articulo aprenderas a actualizar registros en MySQL desde Java.
Escrito por Eduardo Lázaro
