50% OFF Plus
--:--:--
¡Obtener!

Inserción de datos

Intermedio
SpringBoot
SpringBoot
Actualizado: 13/06/2025

¡Desbloquea el curso de SpringBoot completo!

IA
Ejercicios
Certificado
Entrar

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 Plus

Guardar con save()

El método save() es la forma más directa de persistir una entidad en la base de datos utilizando Spring Data JPA. Este método forma parte de la interfaz JpaRepository y se encarga de determinar automáticamente si debe realizar una inserción o una actualización según el estado de la entidad.

Funcionamiento básico del método save()

Cuando invocamos save(), Spring Data JPA examina la entidad para decidir qué operación realizar. Si la entidad tiene un identificador nulo o no existe en la base de datos, se ejecuta una inserción. En caso contrario, se realiza una actualización.

@Entity
public class Usuario {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String nombre;
    private String email;
    
    // Constructores, getters y setters
    public Usuario() {}
    
    public Usuario(String nombre, String email) {
        this.nombre = nombre;
        this.email = email;
    }
    
    // Getters y setters omitidos por brevedad
}

Para utilizar el método save(), necesitamos crear un repositorio que extienda de JpaRepository:

@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {
    // Spring Data JPA proporciona automáticamente el método save()
}

Inserción de una nueva entidad

Cuando creamos una nueva entidad sin especificar un identificador, el método save() la inserta en la base de datos:

@Service
public class UsuarioService {
    
    @Autowired
    private UsuarioRepository usuarioRepository;
    
    public Usuario crearUsuario(String nombre, String email) {
        // Crear nueva entidad sin ID
        Usuario nuevoUsuario = new Usuario(nombre, email);
        
        // El método save() detecta que es una nueva entidad e inserta
        Usuario usuarioGuardado = usuarioRepository.save(nuevoUsuario);
        
        // La entidad retornada incluye el ID generado automáticamente
        return usuarioGuardado;
    }
}

Es importante destacar que el método save() retorna la entidad persistida, que incluye el identificador generado por la base de datos. Este comportamiento es fundamental cuando trabajamos con claves primarias autogeneradas.

Ejemplo práctico en un controlador

Veamos cómo integrar el método save() en un controlador REST para crear nuevos usuarios:

@RestController
@RequestMapping("/api/usuarios")
public class UsuarioController {
    
    @Autowired
    private UsuarioService usuarioService;
    
    @PostMapping
    public ResponseEntity<Usuario> crearUsuario(@RequestBody Usuario usuario) {
        // Asegurar que el ID sea null para forzar inserción
        usuario.setId(null);
        
        Usuario usuarioCreado = usuarioService.crearUsuario(
            usuario.getNombre(), 
            usuario.getEmail()
        );
        
        return ResponseEntity.status(HttpStatus.CREATED).body(usuarioCreado);
    }
}

Manejo de la respuesta del método save()

El método save() siempre retorna la entidad gestionada por el contexto de persistencia. Esta entidad contiene todos los valores actualizados, incluyendo los campos generados automáticamente:

public Usuario registrarUsuario(String nombre, String email) {
    Usuario usuario = new Usuario(nombre, email);
    
    // Antes del save(), el ID es null
    System.out.println("ID antes del save: " + usuario.getId()); // null
    
    Usuario usuarioGuardado = usuarioRepository.save(usuario);
    
    // Después del save(), el ID contiene el valor generado
    System.out.println("ID después del save: " + usuarioGuardado.getId()); // 1, 2, 3...
    
    return usuarioGuardado;
}

Consideraciones importantes

Al trabajar con el método save(), debemos tener en cuenta varios aspectos fundamentales:

  • Transaccionalidad: El método save() se ejecuta dentro de una transacción. Si no existe una transacción activa, Spring crea una automáticamente.

  • Detección de entidades nuevas: Spring utiliza la estrategia de verificar si el identificador es null para determinar si es una entidad nueva.

  • Retorno obligatorio: Siempre debemos utilizar la entidad retornada por save(), ya que puede contener valores actualizados por la base de datos.

// Incorrecto - no usar la entidad retornada
Usuario usuario = new Usuario("Ana", "ana@email.com");
usuarioRepository.save(usuario);
// usuario.getId() sigue siendo null

// Correcto - usar la entidad retornada
Usuario usuario = new Usuario("Ana", "ana@email.com");
Usuario usuarioGuardado = usuarioRepository.save(usuario);
// usuarioGuardado.getId() contiene el valor generado

El método save() proporciona una interfaz simple y consistente para la persistencia de entidades, manejando automáticamente los detalles de la inserción y manteniendo la integridad de los datos en nuestra aplicación.

Guardar con saveAll()

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.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

El método saveAll() permite persistir múltiples entidades en una sola operación, optimizando el rendimiento cuando necesitamos insertar varios registros simultáneamente. Este método acepta una colección de entidades y retorna una lista con todas las entidades persistidas.

Sintaxis y funcionamiento básico

El método saveAll() recibe como parámetro un Iterable de entidades, lo que significa que podemos pasarle listas, conjuntos o cualquier colección que implemente esta interfaz:

// Sintaxis básica del método saveAll()
List<Usuario> usuariosGuardados = usuarioRepository.saveAll(listaUsuarios);

Al igual que save(), este método determina automáticamente si cada entidad debe ser insertada o actualizada, aplicando la misma lógica de verificación del identificador para cada elemento de la colección.

Inserción de múltiples entidades nuevas

Cuando trabajamos con varias entidades nuevas, saveAll() resulta más eficiente que realizar múltiples llamadas individuales a save():

@Service
public class UsuarioService {
    
    @Autowired
    private UsuarioRepository usuarioRepository;
    
    public List<Usuario> crearMultiplesUsuarios(List<String> nombres, List<String> emails) {
        List<Usuario> nuevosUsuarios = new ArrayList<>();
        
        // Crear lista de entidades nuevas
        for (int i = 0; i < nombres.size(); i++) {
            Usuario usuario = new Usuario(nombres.get(i), emails.get(i));
            nuevosUsuarios.add(usuario);
        }
        
        // Guardar todas las entidades en una sola operación
        List<Usuario> usuariosGuardados = usuarioRepository.saveAll(nuevosUsuarios);
        
        return usuariosGuardados;
    }
}

Ejemplo práctico con datos de inicialización

Un caso común para saveAll() es la carga inicial de datos en la aplicación, como poblar catálogos o crear registros de prueba:

@Component
public class DataInitializer {
    
    @Autowired
    private UsuarioRepository usuarioRepository;
    
    @PostConstruct
    public void inicializarDatos() {
        // Verificar si ya existen datos
        if (usuarioRepository.count() == 0) {
            List<Usuario> usuariosIniciales = Arrays.asList(
                new Usuario("Admin", "admin@empresa.com"),
                new Usuario("Moderador", "mod@empresa.com"),
                new Usuario("Usuario Demo", "demo@empresa.com")
            );
            
            // Insertar todos los usuarios de una vez
            usuarioRepository.saveAll(usuariosIniciales);
            
            System.out.println("Datos iniciales creados correctamente");
        }
    }
}

Integración en controladores REST

Para manejar la creación de múltiples registros desde una API REST, podemos utilizar saveAll() en nuestros controladores:

@RestController
@RequestMapping("/api/usuarios")
public class UsuarioController {
    
    @Autowired
    private UsuarioService usuarioService;
    
    @PostMapping("/batch")
    public ResponseEntity<List<Usuario>> crearMultiplesUsuarios(
            @RequestBody List<Usuario> usuarios) {
        
        // Asegurar que todos los IDs sean null para forzar inserción
        usuarios.forEach(usuario -> usuario.setId(null));
        
        List<Usuario> usuariosCreados = usuarioRepository.saveAll(usuarios);
        
        return ResponseEntity.status(HttpStatus.CREATED).body(usuariosCreados);
    }
}

Manejo de la respuesta y validaciones

El método saveAll() retorna una lista ordenada con todas las entidades persistidas, manteniendo el mismo orden que la colección original:

public List<Usuario> procesarRegistroMasivo(List<Usuario> usuarios) {
    // Validar que la lista no esté vacía
    if (usuarios.isEmpty()) {
        throw new IllegalArgumentException("La lista de usuarios no puede estar vacía");
    }
    
    // Limpiar IDs para asegurar inserción
    usuarios.forEach(usuario -> usuario.setId(null));
    
    List<Usuario> usuariosGuardados = usuarioRepository.saveAll(usuarios);
    
    // Verificar que se guardaron todos los registros
    System.out.println("Registros procesados: " + usuariosGuardados.size());
    
    return usuariosGuardados;
}

Ventajas del método saveAll()

El uso de saveAll() ofrece varios beneficios importantes:

  • Eficiencia: Reduce el número de transacciones y operaciones de base de datos comparado con múltiples llamadas a save().

  • Consistencia: Todas las entidades se procesan dentro de la misma transacción, garantizando atomicidad.

  • Simplicidad: Proporciona una interfaz limpia para operaciones de inserción masiva.

// Menos eficiente - múltiples transacciones
for (Usuario usuario : listaUsuarios) {
    usuarioRepository.save(usuario); // Una transacción por cada save()
}

// Más eficiente - una sola transacción
List<Usuario> usuariosGuardados = usuarioRepository.saveAll(listaUsuarios);

Consideraciones de rendimiento

Aunque saveAll() es más eficiente que múltiples llamadas individuales, debemos considerar el tamaño de la colección. Para conjuntos muy grandes de datos, es recomendable procesar los registros en lotes:

public void guardarEnLotes(List<Usuario> usuarios, int tamanoLote) {
    for (int i = 0; i < usuarios.size(); i += tamanoLote) {
        int fin = Math.min(i + tamanoLote, usuarios.size());
        List<Usuario> lote = usuarios.subList(i, fin);
        
        usuarioRepository.saveAll(lote);
        
        // Opcional: limpiar el contexto de persistencia para liberar memoria
        entityManager.flush();
        entityManager.clear();
    }
}

El método saveAll() se convierte en una herramienta fundamental cuando necesitamos manejar operaciones de inserción masiva de manera eficiente y manteniendo la integridad transaccional de nuestros datos.

Aprendizajes de esta lección de SpringBoot

  • Comprender el funcionamiento del método save() para insertar o actualizar entidades.
  • Aprender a utilizar saveAll() para persistir múltiples entidades en una sola operación.
  • Conocer la importancia de manejar correctamente los identificadores para forzar inserciones.
  • Entender la gestión de transacciones y la respuesta que retornan estos métodos.
  • Identificar buenas prácticas para la inserción masiva y optimización del rendimiento.

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

⭐⭐⭐⭐⭐
4.9/5 valoración