Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusMé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
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
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.
Aprendizajes de esta lección de SpringBoot
- 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.
Completa este curso de SpringBoot y certifícate
Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs