Real World Example

A Small DAO for ShopEase Orders

Before (or under) Spring Data JPA, many Indian product companies and banks use plain JDBC or JdbcTemplate for hot paths and reports. A DAO (Data Access Object) keeps all SQL in one class and returns domain objects.

public record OrderSummary(long id, String customer, BigDecimal total, String status) {}

public class OrderDao {
    private final DataSource ds;
    public OrderDao(DataSource ds) { this.ds = ds; }

    public List<OrderSummary> findRecentByStatus(String status, int limit) throws SQLException {
        String sql = """
                SELECT o.id, u.name, o.total, o.status
                FROM orders o JOIN users u ON u.id = o.user_id
                WHERE o.status = ?
                ORDER BY o.created_at DESC
                LIMIT ?""";
        try (Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) {
            ps.setString(1, status);
            ps.setInt(2, limit);
            try (ResultSet rs = ps.executeQuery()) {
                List<OrderSummary> result = new ArrayList<>();
                while (rs.next()) {
                    result.add(new OrderSummary(rs.getLong(1), rs.getString(2), rs.getBigDecimal(3), rs.getString(4)));
                }
                return result;
            }
        }
    }

    public boolean markShipped(long orderId) throws SQLException {
        try (Connection con = ds.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "UPDATE orders SET status = 'SHIPPED' WHERE id = ? AND status = 'PAID'")) {
            ps.setLong(1, orderId);
            return ps.executeUpdate() == 1;      // false if not PAID (idempotent, no double shipping)
        }
    }
}

Example

Calling it from a small admin tool:

dao.findRecentByStatus("PAID", 3).forEach(System.out::println);
dao.markShipped(1043);
dao.markShipped(1043);

Example output

OrderSummary[id=1045, customer=Anita Rao, total=2499.00, status=PAID]
OrderSummary[id=1044, customer=Ravi Kumar, total=799.00, status=PAID]
OrderSummary[id=1043, customer=John Mathew, total=15999.00, status=PAID]
true
false

Spring JdbcTemplate

List<OrderSummary> orders = jdbcTemplate.query(
        "SELECT id, customer, total, status FROM order_summary WHERE status = ?",
        (rs, rowNum) -> new OrderSummary(rs.getLong("id"), rs.getString("customer"),
                                         rs.getBigDecimal("total"), rs.getString("status")),
        "PAID");

Tip: JdbcTemplate removes the try/catch/close boilerplate and turns SQLException into Spring's unchecked DataAccessException hierarchy.