Browser docs

Data Access Object

Intent

Object provides an abstract interface to some type of database or other persistence mechanism.

Explanation

Real world example

There’s a set of customers that need to be persisted to database. Additionally we need the whole set of CRUD (create/read/update/delete) operations so we can operate on customers easily.

In plain words

DAO is an interface we provide over the base persistence mechanism.

Wikipedia says

In computer software, a data access object (DAO) is a pattern that provides an abstract interface to some type of database or other persistence mechanism.

Programmatic Example

Walking through our customers example, here’s the basic Customer entity.

 1public class Customer {
 2
 3  private int id;
 4  private String firstName;
 5  private String lastName;
 6
 7  public Customer(int id, String firstName, String lastName) {
 8    this.id = id;
 9    this.firstName = firstName;
10    this.lastName = lastName;
11  }
12  // getters and setters ->
13  ...
14}

Here’s the CustomerDao interface and two different implementations for it. InMemoryCustomerDao keeps a simple map of customers in memory while DBCustomerDao is the real RDBMS implementation.

 1public interface CustomerDao {
 2
 3  Stream<Customer> getAll() throws Exception;
 4
 5  Optional<Customer> getById(int id) throws Exception;
 6
 7  boolean add(Customer customer) throws Exception;
 8
 9  boolean update(Customer customer) throws Exception;
10
11  boolean delete(Customer customer) throws Exception;
12}
13
14public class InMemoryCustomerDao implements CustomerDao {
15
16  private final Map<Integer, Customer> idToCustomer = new HashMap<>();
17
18  // implement the interface using the map
19  ...
20}
21
22@Slf4j
23public class DbCustomerDao implements CustomerDao {
24
25  private final DataSource dataSource;
26
27  public DbCustomerDao(DataSource dataSource) {
28    this.dataSource = dataSource;
29  }
30
31  // implement the interface using the data source
32  ...

Finally here’s how we use our DAO to manage customers.

 1    final var dataSource = createDataSource();
 2    createSchema(dataSource);
 3    final var customerDao = new DbCustomerDao(dataSource);
 4    
 5    addCustomers(customerDao);
 6    log.info(ALL_CUSTOMERS);
 7    try (var customerStream = customerDao.getAll()) {
 8      customerStream.forEach((customer) -> log.info(customer.toString()));
 9    }
10    log.info("customerDao.getCustomerById(2): " + customerDao.getById(2));
11    final var customer = new Customer(4, "Dan", "Danson");
12    customerDao.add(customer);
13    log.info(ALL_CUSTOMERS + customerDao.getAll());
14    customer.setFirstName("Daniel");
15    customer.setLastName("Danielson");
16    customerDao.update(customer);
17    log.info(ALL_CUSTOMERS);
18    try (var customerStream = customerDao.getAll()) {
19      customerStream.forEach((cust) -> log.info(cust.toString()));
20    }
21    customerDao.delete(customer);
22    log.info(ALL_CUSTOMERS + customerDao.getAll());
23    
24    deleteSchema(dataSource);

The program output:

 1customerDao.getAllCustomers(): 
 2Customer{id=1, firstName='Adam', lastName='Adamson'}
 3Customer{id=2, firstName='Bob', lastName='Bobson'}
 4Customer{id=3, firstName='Carl', lastName='Carlson'}
 5customerDao.getCustomerById(2): Optional[Customer{id=2, firstName='Bob', lastName='Bobson'}]
 6customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@7cef4e59
 7customerDao.getAllCustomers(): 
 8Customer{id=1, firstName='Adam', lastName='Adamson'}
 9Customer{id=2, firstName='Bob', lastName='Bobson'}
10Customer{id=3, firstName='Carl', lastName='Carlson'}
11Customer{id=4, firstName='Daniel', lastName='Danielson'}
12customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@2db0f6b2
13customerDao.getAllCustomers(): 
14Customer{id=1, firstName='Adam', lastName='Adamson'}
15Customer{id=2, firstName='Bob', lastName='Bobson'}
16Customer{id=3, firstName='Carl', lastName='Carlson'}
17customerDao.getCustomerById(2): Optional[Customer{id=2, firstName='Bob', lastName='Bobson'}]
18customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@12c8a2c0
19customerDao.getAllCustomers(): 
20Customer{id=1, firstName='Adam', lastName='Adamson'}
21Customer{id=2, firstName='Bob', lastName='Bobson'}
22Customer{id=3, firstName='Carl', lastName='Carlson'}
23Customer{id=4, firstName='Daniel', lastName='Danielson'}
24customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@6ec8211c

Class diagram

alt text

Applicability

Use the Data Access Object in any of the following situations:

  • When you want to consolidate how the data layer is accessed.
  • When you want to avoid writing multiple data retrieval/persistence layers.

Tutorials

Credits