DEV Community

Cover image for The DAO Design Pattern in Java / Spring Boot
Bora Karaca
Bora Karaca

Posted on • Updated on

The DAO Design Pattern in Java / Spring Boot

The DAO (Data Access Object) design pattern is a popular way of separating the persistence layer from the rest of your application. It provides a way to abstract away the details of database operations, and helps improve the maintainability and testability of your code.

In this blog post, we'll explore the DAO pattern in Java/Spring Boot, and provide code examples to illustrate how it works.

Setting up the Project

To get started with the DAO pattern in Java/Spring Boot, you'll need to create a new Spring Boot project and include the necessary dependencies. Here's an example pom.xml file:

<dependencies>
    <!-- Spring Boot dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- H2 database for testing -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
Enter fullscreen mode Exit fullscreen mode

In this example, we've included the spring-boot-starter-web and spring-boot-starter-data-jpa dependencies, which provide the necessary components for building a web application with database access. We've also included the h2 database dependency for testing purposes.

Defining Entities

In the DAO pattern, entities are POJOs that map to tables in a relational database. To define an entity in Spring Boot, you'll need to create a class with appropriate annotations, such as @Entity, @Table, and @Id. Here's an example:

@Entity
@Table(name = "customers")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;

    private String lastName;

    // getters and setters
}

Enter fullscreen mode Exit fullscreen mode

In this example, we've defined a Customer entity that maps to a customers table in the database. We've used the @Id and @GeneratedValue annotations to specify the primary key, and included firstName and lastName fields.

Defining DAO Interfaces

Once you've defined your entities, you can create DAO interfaces that define the operations that can be performed on the database. Here's an example DAO interface for the Customer entity:

public interface CustomerDao {

    List<Customer> getAll();

    Optional<Customer> getById(Long id);

    Customer save(Customer customer);

    void delete(Customer customer);
}

Enter fullscreen mode Exit fullscreen mode

In this example, we've defined a CustomerDao interface that includes methods for getting all customers, getting a customer by ID, saving a customer, and deleting a customer.

Implementing DAO Interfaces

To implement a DAO interface, you'll need to create a class that provides the actual implementation of the methods. Here's an example implementation of the CustomerDao interface:

@Repository
public class CustomerDaoImpl implements CustomerDao {

    @Autowired
    private EntityManager entityManager;

    @Override
    public List<Customer> getAll() {
        return entityManager.createQuery("SELECT c FROM Customer c", Customer.class).getResultList();
    }

    @Override
    public Optional<Customer> getById(Long id) {
        return Optional.ofNullable(entityManager.find(Customer.class, id));
    }

    @Override
    public Customer save(Customer customer) {
        return entityManager.merge(customer);
    }

    @Override
    public void delete(Customer customer) {
        entityManager.remove(customer);
    }
}

Enter fullscreen mode Exit fullscreen mode

In this example, we've implemented the CustomerDao interface using the EntityManager provided by Spring Boot's JPA implementation. We've used the @Repository annotation to indicate that this class should be treated as a repository component by Spring Boot.

The getAll() method uses the createQuery() method of the EntityManager to retrieve all Customer entities from the database. The getById() method uses the find() method of the EntityManager to retrieve a Customer entity by ID. The save() method uses the merge() method of the EntityManager to save a new or updated Customer entity to the database. The delete() method uses the remove() method of the EntityManager to delete a Customer entity from the database.

Using DAO Interfaces

Now that we've defined and implemented our DAO interface, we can use it in our application to perform database operations. Here's an example of how to use the CustomerDao interface in a controller class:

@RestController
@RequestMapping("/customers")
public class CustomerController {

    @Autowired
    private CustomerDao customerDao;

    @GetMapping
    public List<Customer> getAllCustomers() {
        return customerDao.getAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<Customer> getCustomerById(@PathVariable Long id) {
        Optional<Customer> customer = customerDao.getById(id);
        if (customer.isPresent()) {
            return ResponseEntity.ok(customer.get());
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    @PostMapping
    public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
        Customer savedCustomer = customerDao.save(customer);
        return ResponseEntity.created(URI.create("/customers/" + savedCustomer.getId())).body(savedCustomer);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Customer> updateCustomer(@PathVariable Long id, @RequestBody Customer customer) {
        Optional<Customer> existingCustomer = customerDao.getById(id);
        if (existingCustomer.isPresent()) {
            customer.setId(id);
            Customer savedCustomer = customerDao.save(customer);
            return ResponseEntity.ok(savedCustomer);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteCustomer(@PathVariable Long id) {
        Optional<Customer> customer = customerDao.getById(id);
        if (customer.isPresent()) {
            customerDao.delete(customer.get());
            return ResponseEntity.noContent().build();
        } else {
            return ResponseEntity.notFound().build();
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

In this example, we've created a CustomerController class that uses the CustomerDao interface to perform CRUD (create, read, update, delete) operations on the Customer** entity. We've used the @Autowired annotation to inject an instance of the CustomerDao interface into the controller.

The getAllCustomers() method returns a list of all customers. The getCustomerById() method retrieves a customer by ID. The createCustomer() method saves a new customer. The updateCustomer() method updates an existing customer. The deleteCustomer() method deletes a customer.

Conclusion

The DAO pattern is a powerful way to abstract away the details of database operations and improve the maintainability and testability of your code. I hope this has been helpful, and that you're now able to use the DAO pattern in your own projects.

Top comments (0)