Implementing Data Access Object Pattern in Java Applications
DAO (Data Access Object) defines an abstraction layer for database interactions, separating business logic from data persistence mechanisms. This pattern centralizes data operations into a dedicated API, shielding application code from direct database dependencies.
In practice, a DAO interface declares atomic operations like create, read, update, and delete methods. Concrete implementations handle the actual database communication, while entity classes mirror database table structures.
Typical project organization includes:
- Entity classes in packages like
modelorentity - DAO interfaces and implementations in
daoorrepositorypackages - Business logic consuming DAO interfaces rather than concrete implementations
Consider this entity representing a user:
public class User implements Serializable {
private Long userId;
private String username;
private String email;
private LocalDate registrationDate;
private Boolean activeStatus;
// Getters and setters omitted for brevity
}
A corresponding DAO interface defines operations:
public interface UserDao {
int insertUser(User user);
int removeUser(Long userId);
User findUserById(Long userId);
List<User> findAllUsers();
}
The implementation handles database connectivity:
public class UserDaoImpl implements UserDao {
private final String dbDriver = "com.mysql.cj.jdbc.Driver";
private final String connectionUrl = "jdbc:mysql://localhost:3306/appdb?useSSL=false";
private final String dbUser = "appuser";
private final String dbPassword = "securepass";
@Override
public int insertUser(User user) {
Connection conn = null;
PreparedStatement stmt = null;
int affectedRows = 0;
try {
Class.forName(dbDriver);
conn = DriverManager.getConnection(connectionUrl, dbUser, dbPassword);
String sql = "INSERT INTO users VALUES (NULL, ?, ?, ?, ?)";
stmt = conn.prepareStatement(sql);
stmt.setString(1, user.getUsername());
stmt.setString(2, user.getEmail());
stmt.setDate(3, Date.valueOf(user.getRegistrationDate()));
stmt.setBoolean(4, user.getActiveStatus());
affectedRows = stmt.executeUpdate();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
closeResources(stmt, conn);
}
return affectedRows;
}
@Override
public int removeUser(Long userId) {
Connection conn = null;
PreparedStatement stmt = null;
int result = 0;
try {
Class.forName(dbDriver);
conn = DriverManager.getConnection(connectionUrl, dbUser, dbPassword);
String deleteQuery = "DELETE FROM users WHERE user_id = ?";
stmt = conn.prepareStatement(deleteQuery);
stmt.setLong(1, userId);
result = stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResources(stmt, conn);
}
return result;
}
private void closeResources(PreparedStatement ps, Connection c) {
try {
if (ps != null) ps.close();
if (c != null) c.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// Other interface method implementations would follow similar patterns
}
Frameworks like MyBatis or Spring Data JPA provide higher-level abstractions that reduce boilerplate code while maintaining the separation of concerns that DAO promotes.