java – Code that lists and inserts data to database: Make methods more reusable in superclass

I’m trying to make some methods more reusable and have now three classes that work together: AbstractDao (the superclass), MemberDao (extends AbstractDao) and ProjectTaskDao (extendsAbstractDao). The method insert is very similar in both subclasses with some minor differences:

insert method in MemberDao:

public void insert(Member member) throws SQLException {
try (Connection connection = dataSource.getConnection()){
    try(PreparedStatement statement = connection.prepareStatement(
            "INSERT INTO members (member_name, email) values (?, ?)",
            Statement.RETURN_GENERATED_KEYS
    )){
        statement.setString(1, member.getName());
        statement.setString(2, member.getEmail());
        statement.executeUpdate();

        try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
            generatedKeys.next();
            member.setId(generatedKeys.getLong("id"));
        }
    }
}

}

insert method in ProjectTaskDao:

public void insert(ProjectTask task) throws SQLException {
try (Connection connection = dataSource.getConnection()){
    try(PreparedStatement statement = connection.prepareStatement(
            "INSERT INTO project_tasks (task_name) values (?)",
            Statement.RETURN_GENERATED_KEYS
    )){
        statement.setString(1, task.getName());
        statement.executeUpdate();

        try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
            generatedKeys.next();
            task.setId(generatedKeys.getLong("id"));
        }
    }
}

}

Thesee methods do the same with some minor differences with the “statement.setSomething()”. I`m not that advanced in Java yet so I’m kind of stuck on this. I would also like to pull these methods in as well:

list method in MemberDao:

public List<Member> list() throws SQLException {
List<Member>  members = new ArrayList<>();
try (Connection connection = dataSource.getConnection()) {
    try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM members")) {
        try (ResultSet rs = statement.executeQuery()) {
            while (rs.next()) {
                Member member = new Member();
                member.setName(rs.getString("member_name"));
                members.add(mapRow(rs));
            }
        }
    }
}
return members;

}

list method in ProjectTaskDao:

public List<ProjectTask> list() throws SQLException {
List<ProjectTask>  tasks = new ArrayList<>();
try (Connection connection = dataSource.getConnection()) {
    try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM project_tasks")) {
        try (ResultSet rs = statement.executeQuery()) {
            while (rs.next()) {
                //ProjectTask projectTask = new ProjectTask();
                //projectTask.setName(rs.getString(""));
                tasks.add(mapRow(rs));
            }
        }
    }
}
return tasks;

}

And here is the whole superclass as it stands currently:

public abstract class AbstractDao<T> {
protected final DataSource dataSource;

public AbstractDao(DataSource dataSource) {
    this.dataSource = dataSource;
}

protected T retrieve(Long id, String sql) throws SQLException {
    try (Connection connection = dataSource.getConnection()) {
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setLong(1, id);
            try (ResultSet rs = statement.executeQuery()) {
                if (rs.next()) {
                    return mapRow(rs);
                } else {
                    return null;
                }

            }
        }
    }
}

protected abstract T mapRow(ResultSet rs) throws SQLException;

}

Let me know if you need more information to help! Thanks ­čśÇ