Hard vs Soft Delete, Pitfalls & Refactoring
Master hard vs soft deletion strategies, state transitions, query performance matrices, production pitfalls, engineering checklists, and refactoring God Controllers.
Hard vs Soft Delete, Pitfalls & Refactoring
Deleting records from a database is a critical architectural decision. Spring Boot CRUD applications support two deletion models: Hard Delete and Soft Delete.
1. Hard Delete vs Soft Delete Mechanics
Database Table: students
Before Deletion:
id | name | email | is_deleted
---+---------------+───────────────────+-----------
1 | Rahul Sharma | [email protected] | false
2 | Amit Kumar | [email protected] | false
HARD DELETE (DELETE FROM students WHERE id = 1):
id | name | email | is_deleted
---+---------------+───────────────────+-----------
2 | Amit Kumar | [email protected] | false <-- Row 1 is permanently destroyed!
SOFT DELETE (UPDATE students SET is_deleted = true WHERE id = 1):
id | name | email | is_deleted
---+---------------+───────────────────+-----------
1 | Rahul Sharma | [email protected] | true <-- Row retained for audit trail!
2 | Amit Kumar | [email protected] | falseImplementation Comparison
// Hard Delete (Permanent DB Row Removal)
public void hardDeleteStudent(Long id) {
if (!studentRepository.existsById(id)) {
throw new RuntimeException("Student not found: " + id);
}
studentRepository.deleteById(id);
}
// Soft Delete (State Flag Mutation)
public Student softDeleteStudent(Long id) {
Student student = getStudentById(id);
student.setDeleted(true); // Mutate flag
return studentRepository.save(student); // Persist updated state
}Deletion Strategy Trade-Off Matrix
| Metric | Hard Delete (deleteById) | Soft Delete (is_deleted = true) |
|---|---|---|
| Database Row | Physically removed | Retained in storage |
| Data Recoverability | Irrecoverable (unless restored from backup) | Fully recoverable (is_deleted = false) |
| Storage Growth | Minimal | Continuous table expansion |
| Query Complexity | Standard SQL queries | Queries must filter WHERE is_deleted = false |
| Compliance / Audit | Poor for financial/legal records | Required for compliance and audit logging |
2. Entity State Transition Model
POST /api/students (Create)
│
▼
┌──────────────┐
│ ACTIVE STATE │ (is_deleted = false)
└──────┬───────┘
│
┌─────────────────┴─────────────────┐
│ │
PUT /api/students/{id} DELETE /api/students/{id} (Soft)
(Update) │
│ ▼
▼ ┌──────────────┐
┌──────────────┐ │ DELETED STATE│ (is_deleted = true)
│ ACTIVE STATE │ └──────┬───────┘
└──────────────┘ │
│ Restore Operation
▼
┌──────────────┐
│ ACTIVE STATE │ (is_deleted = false)
└──────────────┘3. Database Operation Complexity Matrix
| Endpoint | Application Intent | SQL Executed | DB Performance Cost | Index Requirement |
|---|---|---|---|---|
POST /api/students | Insert Record | INSERT INTO ... | Low (1 Row Write) | Primary Key Auto-Increment Index |
GET /api/students/{id} | Read Single | SELECT ... WHERE id = ? | Very Low (O(1) / O(log N)) | Primary Key Index |
GET /api/students | Read All | SELECT ... WHERE is_deleted=false | High on Large Tables | Index on is_deleted column |
PUT /api/students/{id} | Update Record | SELECT then UPDATE | Medium (1 Read + 1 Write) | Primary Key Index |
DELETE /api/students/{id} | Soft Delete | UPDATE ... SET is_deleted=true | Medium (1 Read + 1 Write) | Primary Key Index |
[!WARNING] Performance Pitfall: Calling
findAll()on a production table with millions of rows consumes massive memory, network bandwidth, and CPU cycles. Always implement Pagination usingPageablein production APIs!
4. Production Pitfalls & Engineering Checklist
5 Critical Pitfalls
- God Controller: Putting database queries and business rules inside
@RestControllermethods. - Unbounded
findAll(): Returning entire database tables without pagination. - Ignoring Missing IDs: Invoking
repository.findById(id).get()without handling emptyOptionalresults. - Naming Inconsistencies: Mixing
courseandsubjectacross DTOs, Entities, and SQL columns. - Passive Database Assumptions: Adding JPA starters without providing
spring.datasource.url, causing startup crashes.
Engineering Checklist
- REST endpoints follow HTTP verb standards (
POST,GET,PUT,DELETE). - Controller delegates all business logic to Service.
- Repository inherits from
JpaRepository<Student, Long>. -
@Entityhas@Idwith@GeneratedValue(strategy = GenerationType.IDENTITY). -
@PathVariablehandles URL path IDs. -
@RequestBodyhandles incoming JSON bodies. - Soft delete filters out
isDeleted = truerecords in queries. - Connection parameters configured in
application.properties.
❓ Interactive Self-Assessment
What is the main advantage of soft deletion over hard deletion in enterprise systems?
What risk occurs when calling repository.findById(id).get() directly?
Refactoring the God Controller
A legacy Spring Boot application has a StudentController that executes raw SQL via JDBC, validates inputs, applies business rules, and performs soft deletion logic directly inside the controller class. Refactor this architecture into clean, decoupled layers.
REST Mapping & CRUD Operations
Master REST endpoint mapping, HTTP verbs, @PathVariable, @RequestBody, Create/Read/Update pipelines, and end-to-end request-to-database execution chains.
ORM, Hibernate Mechanics & DataSource Configuration
Master Object-Relational Impedance Mismatch, JPA specification vs Hibernate implementation, JDBC URL breakdown, ddl-auto strategies, and database migration tooling.