SpringBoot
Tutorial SpringBoot: Borrar datos de base de datos
Aprende a eliminar datos en base de datos usando métodos delete en Spring Data JPA con buenas prácticas y manejo de asociaciones.
Aprende SpringBoot y certifícateMétodos delete en repositorios
Spring Data JPA proporciona múltiples formas de eliminar entidades de la base de datos a través de los repositorios. Estas operaciones van desde métodos simples hasta consultas personalizadas que permiten borrar registros según criterios específicos.
Métodos básicos de eliminación
El repositorio base de Spring Data JPA incluye varios métodos predefinidos para eliminar entidades. El más directo es deleteById()
, que elimina una entidad utilizando su identificador único:
@Service
public class ProductoService {
@Autowired
private ProductoRepository productoRepository;
public void eliminarProducto(Long id) {
productoRepository.deleteById(id);
}
}
También puedes eliminar una entidad completa utilizando el método delete()
, que recibe la instancia del objeto:
public void eliminarProductoCompleto(Producto producto) {
productoRepository.delete(producto);
}
Para eliminar múltiples entidades de una vez, Spring Data JPA ofrece deleteAll()
con diferentes variantes:
// Eliminar todas las entidades
public void eliminarTodosLosProductos() {
productoRepository.deleteAll();
}
// Eliminar una colección específica de entidades
public void eliminarProductosSeleccionados(List<Producto> productos) {
productoRepository.deleteAll(productos);
}
Métodos de consulta personalizados
Spring Data JPA permite crear métodos de eliminación personalizados utilizando la convención de nombres. Estos métodos siguen el patrón deleteBy
seguido del nombre de la propiedad:
public interface ProductoRepository extends JpaRepository<Producto, Long> {
// Eliminar por categoría
void deleteByCategoriaId(Long categoriaId);
// Eliminar por precio menor a un valor
void deleteByPrecioLessThan(BigDecimal precio);
// Eliminar por nombre que contenga una cadena
void deleteByNombreContaining(String texto);
}
Para utilizar estos métodos personalizados, es importante marcarlos con la anotación @Transactional
en el servicio:
@Service
@Transactional
public class ProductoService {
@Autowired
private ProductoRepository productoRepository;
public void eliminarProductosPorCategoria(Long categoriaId) {
productoRepository.deleteByCategoriaId(categoriaId);
}
public void eliminarProductosBaratos(BigDecimal precioMaximo) {
productoRepository.deleteByPrecioLessThan(precioMaximo);
}
}
Consultas JPQL para eliminación
Para casos más complejos, puedes utilizar consultas JPQL personalizadas con la anotación @Query
y @Modifying
:
public interface ProductoRepository extends JpaRepository<Producto, Long> {
@Modifying
@Query("DELETE FROM Producto p WHERE p.fechaCreacion < :fecha")
int eliminarProductosAntiguos(@Param("fecha") LocalDateTime fecha);
@Modifying
@Query("DELETE FROM Producto p WHERE p.categoria.nombre = :nombreCategoria")
int eliminarPorNombreCategoria(@Param("nombreCategoria") String nombreCategoria);
}
El uso de @Modifying
es obligatorio para operaciones de modificación como DELETE. Esta anotación indica a Spring que la consulta modifica datos en lugar de solo leerlos.
Verificación antes de eliminar
Es una buena práctica verificar la existencia de una entidad antes de intentar eliminarla. Spring Data JPA proporciona métodos útiles para esta validación:
@Service
@Transactional
public class ProductoService {
@Autowired
private ProductoRepository productoRepository;
public boolean eliminarProductoSiExiste(Long id) {
if (productoRepository.existsById(id)) {
productoRepository.deleteById(id);
return true;
}
return false;
}
public void eliminarProductoConValidacion(Long id) {
Producto producto = productoRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Producto no encontrado"));
productoRepository.delete(producto);
}
}
Eliminación en lote optimizada
Para operaciones masivas, Spring Data JPA ofrece métodos más eficientes que ejecutan una sola consulta SQL en lugar de múltiples operaciones individuales:
public interface ProductoRepository extends JpaRepository<Producto, Long> {
@Modifying
@Query("DELETE FROM Producto p WHERE p.id IN :ids")
int eliminarPorIds(@Param("ids") List<Long> ids);
@Modifying
@Query("DELETE FROM Producto p WHERE p.activo = false")
int eliminarProductosInactivos();
}
Estos métodos devuelven un int
que representa el número de registros eliminados, información útil para confirmar el resultado de la operación:
@Service
@Transactional
public class ProductoService {
public int limpiarProductosInactivos() {
int eliminados = productoRepository.eliminarProductosInactivos();
System.out.println("Se eliminaron " + eliminados + " productos inactivos");
return eliminados;
}
}
Consideraciones al borrar con asociaciones
Cuando trabajas con entidades que tienen relaciones entre sí, eliminar datos se convierte en una operación más compleja que requiere especial atención. Las asociaciones JPA pueden generar restricciones de integridad referencial que impiden el borrado directo, o pueden provocar efectos en cascada no deseados.
Restricciones de clave foránea
El problema más común al eliminar entidades relacionadas son las restricciones de clave foránea. Si intentas eliminar una entidad que es referenciada por otras, la base de datos lanzará una excepción:
@Entity
public class Categoria {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombre;
@OneToMany(mappedBy = "categoria")
private List<Producto> productos = new ArrayList<>();
}
@Entity
public class Producto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombre;
@ManyToOne
@JoinColumn(name = "categoria_id")
private Categoria categoria;
}
Si intentas eliminar una categoría que tiene productos asociados, obtendrás un error de violación de restricción:
@Service
@Transactional
public class CategoriaService {
public void eliminarCategoria(Long categoriaId) {
// Esto fallará si la categoría tiene productos
categoriaRepository.deleteById(categoriaId);
}
}
Estrategias de eliminación en cascada
JPA ofrece la opción cascade = CascadeType.REMOVE
para propagar automáticamente las operaciones de eliminación a las entidades relacionadas:
@Entity
public class Categoria {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombre;
@OneToMany(mappedBy = "categoria", cascade = CascadeType.REMOVE)
private List<Producto> productos = new ArrayList<>();
}
Con esta configuración, eliminar una categoría eliminará automáticamente todos sus productos asociados:
@Service
@Transactional
public class CategoriaService {
public void eliminarCategoriaConProductos(Long categoriaId) {
// Eliminará la categoría y todos sus productos
categoriaRepository.deleteById(categoriaId);
}
}
Sin embargo, esta aproximación puede ser peligrosa si no es el comportamiento deseado, ya que podrías eliminar datos importantes sin darte cuenta.
Eliminación manual de dependencias
Una estrategia más controlada consiste en eliminar manualmente las entidades dependientes antes de eliminar la entidad principal:
@Service
@Transactional
public class CategoriaService {
@Autowired
private CategoriaRepository categoriaRepository;
@Autowired
private ProductoRepository productoRepository;
public void eliminarCategoriaSegura(Long categoriaId) {
// Primero eliminar todos los productos de la categoría
productoRepository.deleteByCategoriaId(categoriaId);
// Después eliminar la categoría
categoriaRepository.deleteById(categoriaId);
}
}
Validación antes de eliminar
Es recomendable verificar las dependencias antes de proceder con la eliminación, especialmente en aplicaciones donde los datos tienen valor crítico:
@Service
@Transactional
public class CategoriaService {
public void eliminarCategoriaConValidacion(Long categoriaId) {
// Verificar si la categoría tiene productos
long cantidadProductos = productoRepository.countByCategoriaId(categoriaId);
if (cantidadProductos > 0) {
throw new IllegalStateException(
"No se puede eliminar la categoría porque tiene " +
cantidadProductos + " productos asociados"
);
}
categoriaRepository.deleteById(categoriaId);
}
}
Eliminación lógica como alternativa
En lugar de eliminar físicamente los registros, puedes implementar eliminación lógica mediante un campo booleano que marque los registros como inactivos:
@Entity
public class Categoria {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombre;
@Column(name = "activo")
private boolean activo = true;
@OneToMany(mappedBy = "categoria")
private List<Producto> productos = new ArrayList<>();
}
Esta aproximación preserva la integridad referencial mientras permite "eliminar" entidades de forma segura:
@Service
@Transactional
public class CategoriaService {
public void desactivarCategoria(Long categoriaId) {
Categoria categoria = categoriaRepository.findById(categoriaId)
.orElseThrow(() -> new EntityNotFoundException("Categoría no encontrada"));
categoria.setActivo(false);
categoriaRepository.save(categoria);
}
}
Configuración de acciones referenciales
Puedes configurar el comportamiento de las claves foráneas a nivel de base de datos utilizando las anotaciones de JPA:
@Entity
public class Producto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nombre;
@ManyToOne
@JoinColumn(name = "categoria_id",
foreignKey = @ForeignKey(name = "fk_producto_categoria"))
private Categoria categoria;
}
Para casos específicos, puedes usar @OnDelete
de Hibernate para definir acciones a nivel de base de datos:
@Entity
public class Producto {
@ManyToOne
@JoinColumn(name = "categoria_id")
@OnDelete(action = OnDeleteAction.SET_NULL)
private Categoria categoria;
}
Manejo de relaciones bidireccionales
En relaciones bidireccionales, es importante mantener la coherencia al eliminar entidades. Debes actualizar ambos lados de la relación:
@Service
@Transactional
public class ProductoService {
public void eliminarProductoDeCategoria(Long productoId) {
Producto producto = productoRepository.findById(productoId)
.orElseThrow(() -> new EntityNotFoundException("Producto no encontrado"));
// Remover la referencia del lado de la categoría
if (producto.getCategoria() != null) {
producto.getCategoria().getProductos().remove(producto);
}
// Eliminar el producto
productoRepository.delete(producto);
}
}
Esta gestión cuidadosa de las asociaciones garantiza que las operaciones de eliminación se ejecuten correctamente sin comprometer la integridad de los datos ni generar efectos secundarios inesperados.
Otras lecciones de SpringBoot
Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Spring Boot
Introducción Y Entorno
Spring Boot Starters
Introducción Y Entorno
Inyección De Dependencias
Introducción Y Entorno
Crear Proyecto Con Spring Initializr
Introducción Y Entorno
Crear Proyecto Desde Visual Studio Code
Introducción Y Entorno
Controladores Spring Mvc
Spring Mvc Con Thymeleaf
Vista En Spring Mvc Con Thymeleaf
Spring Mvc Con Thymeleaf
Controladores Spring Rest
Spring Mvc Con Thymeleaf
Open Api Y Cómo Agregarlo En Spring Boot
Spring Mvc Con Thymeleaf
Servicios En Spring
Spring Mvc Con Thymeleaf
Clientes Resttemplate Y Restclient
Spring Mvc Con Thymeleaf
Rxjava En Spring Web
Spring Mvc Con Thymeleaf
Métodos Post En Controladores Mvc
Spring Mvc Con Thymeleaf
Métodos Get En Controladores Mvc
Spring Mvc Con Thymeleaf
Formularios En Spring Mvc
Spring Mvc Con Thymeleaf
Crear Proyecto Con Intellij Idea
Spring Mvc Con Thymeleaf
Introducción A Los Modelos Mvc
Spring Mvc Con Thymeleaf
Layouts Y Fragmentos En Thymeleaf
Spring Mvc Con Thymeleaf
Estilización Con Bootstrap Css
Spring Mvc Con Thymeleaf
Gestión De Errores Controlleradvice
Spring Mvc Con Thymeleaf
Estilización Con Tailwind Css
Spring Mvc Con Thymeleaf
Introducción A Controladores Rest
Spring Rest
Métodos Get En Controladores Rest
Spring Rest
Métodos Post En Controladores Rest
Spring Rest
Métodos Delete En Controladores Rest
Spring Rest
Métodos Put Y Patch En Controladores Rest
Spring Rest
Gestión De Errores Restcontrolleradvice
Spring Rest
Creación De Entidades Jpa
Spring Data Jpa
Asociaciones De Entidades Jpa
Spring Data Jpa
Repositorios Spring Data
Spring Data Jpa
Métodos Find En Repositorios
Spring Data Jpa
Inserción De Datos
Spring Data Jpa
Actualizar Datos De Base De Datos
Spring Data Jpa
Borrar Datos De Base De Datos
Spring Data Jpa
Consultas Jpql Con @Query En Spring Data Jpa
Spring Data Jpa
Api Query By Example (Qbe)
Spring Data Jpa
Api Specification
Spring Data Jpa
Repositorios Reactivos
Spring Data Jpa
Configuración Base De Datos Postgresql
Spring Data Jpa
Configuración Base De Datos Mysql
Spring Data Jpa
Introducción A Jpa Y Spring Data Jpa
Spring Data Jpa
Configuración Base De Datos H2
Spring Data Jpa
Testing Unitario De Componentes Y Servicios
Testing Con Spring Test
Testing De Repositorios Spring Data Jpa
Testing Con Spring Test
Testing Controladores Spring Mvc Con Thymeleaf
Testing Con Spring Test
Testing Controladores Rest Con Json
Testing Con Spring Test
Testing De Aplicaciones Reactivas Webflux
Testing Con Spring Test
Testing De Seguridad Spring Security
Testing Con Spring Test
Testing Con Apache Kafka
Testing Con Spring Test
Introducción Al Testing
Testing Con Spring Test
Introducción A Spring Security
Seguridad Con Spring Security
Seguridad Basada En Formulario
Seguridad Con Spring Security
Registro De Usuarios En Api Rest
Seguridad Con Spring Security
Login De Usuarios En Api Rest
Seguridad Con Spring Security
Validación Jwt En Api Rest
Seguridad Con Spring Security
Autenticación Jwt Completa En Api Rest
Seguridad Con Spring Security
Seguridad Jwt En Api Rest Reactiva Spring Webflux
Seguridad Con Spring Security
Autenticación Y Autorización Con Anotaciones
Seguridad Con Spring Security
Fundamentos De Autenticación Oauth
Seguridad Con Spring Security
Autenticación Oauth Con Github
Seguridad Con Spring Security
Testing Con Spring Security Test
Seguridad Con Spring Security
Autenticación Oauth En Api Rest
Seguridad Con Spring Security
Introducción A Spring Webflux
Reactividad Webflux
Spring Data R2dbc
Reactividad Webflux
Controlador Reactivo Basado En Anotaciones
Reactividad Webflux
Controlador Reactivo Basado En Funciones
Reactividad Webflux
Operadores Reactivos Básicos
Reactividad Webflux
Operadores Reactivos Avanzados
Reactividad Webflux
Cliente Reactivo Webclient
Reactividad Webflux
Introducción E Instalación De Apache Kafka
Mensajería Asíncrona
Crear Proyecto Con Apache Kafka
Mensajería Asíncrona
Creación De Producers
Mensajería Asíncrona
Creación De Consumers
Mensajería Asíncrona
Kafka Streams En Spring Boot
Mensajería Asíncrona
Integración Con Angular
Integración Frontend
Integración Con React
Integración Frontend
Integración Con Vue
Integración Frontend
Ejercicios de programación de SpringBoot
Evalúa tus conocimientos de esta lección Borrar datos de base de datos con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Crear entidades JPA
Controladores Spring MVC
Asociaciones de entidades JPA
Creación de entidades
Reto servicio PedidoService
Reto controlador REST
Consultas JPQL
Reto test controlador REST
Anotaciones JPA
Relación ManyToOne con Tarea y Proyecto
CRUD Customers Spring MVC + Spring Data JPA
Backend API REST con Spring Boot
Filtrar categorías por nombre
Reto controlador MVC Categoría
Entidad y repositorio
Métodos derivados y consultas JPQL en repositorios
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender los métodos básicos para eliminar entidades en Spring Data JPA.
- Aprender a crear métodos personalizados de eliminación mediante convenciones y consultas JPQL.
- Conocer las estrategias para manejar asociaciones y restricciones de clave foránea al eliminar datos.
- Identificar buenas prácticas para validar y optimizar operaciones de borrado en lote.
- Entender alternativas como la eliminación lógica para preservar la integridad de los datos.