Abstract
- Data Layer Abstraction separates data access logic from the rest of the application by using an intermediary layer like DO, VO and DAO to interact with databases
Important
Ensures a clear separation between data access and business logic, so schema changes and database switches don’t require significant changes to the business logic.
Centralises security features, such as SQL injection prevention.
DO
id | name | created_at | |
---|---|---|---|
1 | John Doe | john@example.com | 2024-01-01 10:00 |
public class UserDO {
private int id;
private String name;
private String email;
private Timestamp createdAt;
// Getters and Setters
}
- Data Object
- Direct mapping to a database table, used in the DAO layer
- We can obtain an instance of DO using Mapper -
UserDO userDO = userMapper.getUserById(1);
DAO Mapper
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select("SELECT id, name, email FROM users WHERE id = #{id}")
UserDO getUserById(int id);
}
- Data Access Object Mapper
- A DAO mapper is a component that maps data between different layers, typically between the database and the application’s object model, simplifying interactions with data sources and improving code maintainability
VO
id | name | created_at | |
---|---|---|---|
1 | John Doe | john@example.com | 2024-01-01 10:00 |
public class UserVO {
private String name;
private String email;
public UserVO(String name, String email) {
this.name = name;
this.email = email;
}
// Getters only
}
- Value Object
- Encapsulates data relevant to the business domain, and used in application logic
- We usually obtain an instance of VO with data from DO -
UserVO userVO = new UserVO(userDO.getName(), userDO.getEmail());
Why no setters?
VO represents immutable business/domain data.
DTO
id | name | created_at | |
---|---|---|---|
1 | John Doe | john@example.com | 2024-01-01 10:00 |
public class UserDTO {
private String name;
private String email;
private int age;
public UserDTO(UserDO userDO) {
this.name = userDO.getName();
this.email = userDO.getEmail();
this.age = calculateAge(userDO.getCreatedAt());
}
private int calculateAge(Timestamp createdAt) {
return Period.between(createdAt.toLocalDateTime().toLocalDate(), LocalDate.now()).getYears();
}
// Getters only
}
- Data Transfer Object
- Sends formatted data to external systems, often used in APIs
- We usually wrap DO with DAO, so it is formatted and ready to be returned in an API response -
UserDTO userDTO = new UserDTO(userDO);
Why no setters?
DAO transfers formatted, immutable data between layers/systems.