This guide shows how to use
transactions and
rollbacks in
Spring Boot with an
Apache Derby database to keep data consistent.
1. Add Dependencies
In
pom.xml:
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2. Configure Derby
In
application.properties:
spring.datasource.url=jdbc:derby:memory:txDB;create=true
spring.datasource.driver-class-name=org.apache.derby.jdbc.EmbeddedDriver
spring.jpa.hibernate.ddl-auto=create
3. Create Entity
import jakarta.persistence.*;
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String owner;
private double balance;
// getters and setters
}
4. Repository
import org.springframework.data.jpa.repository.JpaRepository;
public interface AccountRepository extends JpaRepository<Account, Long> {
}
5. Transactional Service
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class AccountService {
private final AccountRepository repo;
public AccountService(AccountRepository repo) {
this.repo = repo;
}
@Transactional
public void transfer(Long fromId, Long toId, double amount) {
Account from = repo.findById(fromId).orElseThrow();
Account to = repo.findById(toId).orElseThrow();
from.setBalance(from.getBalance() - amount);
// simulate error
if (amount > 500) {
throw new RuntimeException("Transfer limit exceeded");
}
to.setBalance(to.getBalance() + amount);
repo.save(from);
repo.save(to);
}
}
Here, if the amount is greater than 500, an exception is thrown and
the transaction is rolled back.
6. REST Controller
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/accounts")
public class AccountController {
private final AccountService service;
public AccountController(AccountService service) {
this.service = service;
}
@PostMapping("/transfer")
public String transfer(@RequestParam Long from, @RequestParam Long to, @RequestParam double amount) {
try {
service.transfer(from, to, amount);
return "Transfer successful!";
} catch (Exception e) {
return "Transfer failed: " + e.getMessage();
}
}
}
7. Test
- Create accounts in Derby through JPA.
- Call the API:
curl -X POST "http://localhost:8080/accounts/transfer?from=1&to=2&amount=200"
Works fine.
curl -X POST "http://localhost:8080/accounts/transfer?from=1&to=2&amount=600"
Rolls back automatically.
image quote pre code