Careeroza
Interfaces and Transactions in the Service
Does Every Service Need an Interface?
Older Spring code always wrote ProductService + ProductServiceImpl. Today this is optional: Mockito can mock classes and Spring can proxy classes. Add an interface when there really are several implementations (e.g. PaymentGateway with RazorpayGateway and StripeGateway).
public interface PaymentGateway {
PaymentResult charge(String orderId, BigDecimal amount);
}
@Service
@Profile("prod")
class RazorpayGateway implements PaymentGateway { ... }
@Service
@Profile("dev")
class FakePaymentGateway implements PaymentGateway { ... } // always succeeds, for local testing@Transactional Belongs in the Service
A service method is one business operation, so it is the right place for a transaction: either everything in it is saved, or nothing.
@Service
public class OrderService {
@Transactional // one DB transaction for the whole method
public Order placeOrder(Long userId, List<CartItem> items) {
items.forEach(i -> productService.reserve(i.productId(), i.quantity()));
return orderRepository.save(Order.from(userId, items));
// if save() throws, the stock reservations are rolled back too
}
@Transactional(readOnly = true)
public List<Order> history(Long userId) { return orderRepository.findByUserId(userId); }
}Note: Propagation, isolation and rollback rules are explained in the Hibernate & JPA material (Transactions module).