In this tutorial, we will learn how to use native SQL query to perform delete operations using Spring Data JPA.
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDate;
@Setter
@Getter
@Entity
@Table(name = "persons")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String city;
    private LocalDate birthdate;  // Assuming you have this field
}
Let's create a PersonRepository interface that extends the JpaRepository interface
            from Spring Data JPA:
import com.springdatajpa.springboot.entity.Person;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PersonRepository extends JpaRepository<Person, Long> {
}
Spring Data JPA's @Query annotation is a gateway to native SQL operations
            when its
            nativeQuery attribute is set to true.
        
@Modifying
@Query(value = "DELETE FROM Person WHERE city = ?1", nativeQuery = true)
void deleteByCity(String city);
@Modifying: Informs Spring Data JPA that this query modifies data.
nativeQuery=true: Indicates that the provided query is a native SQL statement.
@Modifying
@Query(value = "DELETE FROM Person WHERE birthdate BETWEEN ?1 AND ?2", nativeQuery = true)
void deleteByBirthdateBetween(LocalDate startDate, LocalDate endDate);
@Modifying
@Query(value = "DELETE FROM Person WHERE name LIKE ?1", nativeQuery = true)
void deleteByNamePattern(String namePattern);
@Modifying
@Query(value = "DELETE FROM Person WHERE id < ?1", nativeQuery = true)
void deleteByIdLessThan(Long id);
@Modifying
@Query(value = "DELETE FROM Person WHERE id < ?1", nativeQuery = true)
void deleteByIdLessThan(Long id);
Note: Native queries skip the ORM layer, so they're generally faster but lack the safety checks that come with using the ORM. Always ensure you understand the implications of your native queries, especially deletions, and thoroughly test them before deploying to a production environment.
Let's see how to use one of the deleteByCity query method in the service
            layer:
@Service
public class PersonService {
    @Autowired
    private PersonRepository personRepository;
    @Transactional
    public void removePersonsByCity(String city) {
        personRepository.deleteByCity(city);
    }
}
The @Transactional annotation is crucial, ensuring atomic operations. If the
            deletion process encounters an
            error, the transaction will be automatically rolled back.
Spring Boot's integrated testing support makes it convenient to validate our implementation:
@SpringBootTest
public class PersonServiceTest {
    @Autowired
    private PersonService personService;
    @Autowired
    private PersonRepository personRepository;
    @Test
    public void testDeleteByCity() {
        // Given: Initial data setup
        personRepository.save(new Person("John", "New York"));
        personRepository.save(new Person("Jane", "Los Angeles"));
        // When: Deleting persons by city
        personService.removePersonsByCity("New York");
        // Then: Assert that only persons from New York are deleted
        List<Person> remainingPersons = personRepository.findAll();
        assertTrue(remainingPersons.stream().noneMatch(person -> "New York".equals(person.getCity())));
    }
}
        In this tutorial, we have learned how to use native SQL query to perform delete operations using Spring Data JPA. Remember, native queries skip the ORM layer, so they're generally faster but lack the safety checks that come with using the ORM. Always ensure you understand the implications of your native queries, especially deletions, and thoroughly test them before deploying to a production environment.