13 · Persistence / LESSON 61 OF 102
Service transactions and durable CRUD
Group changes into one business operation.
Before this lesson: Repositories and pagination
Understand the topic
@Transactional wraps a proxied call in a transaction. Loaded entities are managed; changed fields flush at commit. Runtime exceptions normally roll back. Calling your own method directly can bypass the usual proxy interception.
Inject this service into the controller. Add POST /api/tasks returning a response DTO, 201, and Location using the persisted ID. Add read, paginated list, update, and delete routes. Ownership checks are introduced in the security section.
EXAMPLE · JAVA
src/main/java/com/example/tasks/TaskService.java
package com.example.tasks;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.http.HttpStatus;
@Service
public class TaskService {
private final TaskRepository repository;
private final TitleService titles;
public TaskService(TaskRepository repository, TitleService titles) {
this.repository = repository; this.titles = titles;
}
@Transactional
public Task create(String title) {
return repository.save(new Task(titles.normalize(title)));
}
@Transactional
public void complete(long id) {
Task task = repository.findById(id).orElseThrow(() ->
new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found"));
task.complete();
}
}What to expect
create stores a row; complete updates a managed entity. Call through the injected service bean.
YOUR TURN
Put it into practice
- 01Connect create to POST and return a DTO.
- 02Throw a runtime exception after an update and verify rollback.
- 03Explore @Version for conflicting updates.
Pass a quiz or complete a lab to check today’s streak. Each lesson counts once per day, including when you review it later.
UNDER THE HOOD
Build the mental model
A transaction defines an atomic business change, while isolation and locking govern competing changes.
- 01A managed entity can be dirty-checked and flushed at commit. save is not required after every setter on that managed instance.
- 02Proxy-based transactions apply when calls cross the managed proxy. A direct call from one method to another on the same instance can bypass interception.
- 03Optimistic locking with a version column detects stale updates. It does not automatically decide how the client should resolve the conflict.
A mistake worth avoiding
Do not keep database transactions open during slow external HTTP calls without a deliberate reason.
DEBUGGING ROOM
Something broke. Where do you look?
A method annotated transactional does not roll back as expected when called internally.
Before revealing the diagnosis, write down your first investigation step.
CHECK YOUR UNDERSTANDING
Why can self-invocation bypass transactional behavior?
BUILD IT YOURSELF
Prove atomicity and detect conflicts
- 1.Update two related rows in one service operation.
- 2.Fail between the writes and verify rollback.
- 3.Add a version field and exercise two competing updates.
Acceptance checklist
Lab completion is your self-report. Knowledge checks do not certify project quality.
RETRIEVE IT FROM MEMORY
What is the smallest complete business operation that must be atomic?
Revisit this lesson in three days after a successful check or lab.
Ready for the next step?
Explain commit, rollback, and the service boundary.
Reading is separate from passing a knowledge check or completing a lab.