从链接Postgres to fetch the list having comma separated values中获取参考,我想编写一个查询,该查询将员工电子邮件表字段作为特定员工的列表。为了使Spring Batch能够从结果集中简单地匹配它,并创建一个POJO / Model类,例如为Employee类列出电子邮件?,这是必需的?
这可能吗?
select c.*, ce.*, string_agg(ce.email, ',') as emails
from root.employee c
full outer join root.employee_email ce
on c.employee_id = ce.employee_id
group by
c.employee_id, ce.employee_email_id
order by
c.employee_id
limit 1000
offset 0;
答案 0 :(得分:0)
您的问题是批处理领域中的常见问题,在Spring Batch中,它称为“基于查询的驱动项读取器”,您可以在here中找到有关此问题的更多信息。
基本上,您可以在阅读器中检索联系人,并在处理器中向其中添加电子邮件列表。
@Bean(destroyMethod = "")
public JdbcCursorItemReader<Employee> employeeReader(DataSource dataSource) {
JdbcCursorItemReader<Employee> ItemReader = new JdbcCursorItemReader<>();
ItemReader.setDataSource(dataSource);
ItemReader.setSql("SELECT * FROM employee.employee C ");
ItemReader.setRowMapper(new EmployeeRowMapper());
return ItemReader;
}
@Bean
public ItemProcessor<Employee, Employee> settlementHeaderProcessor(JdbcTemplate jdbcTemplate){
return item -> {
root.EMPLOYEE_EMAIL CE WHERE ce.employee_id = ? ",
new Object[]{item.getId()},
new RowMapper<String>() {
@Override
public String mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("EMAIL");
}
});
item.setEmails(emails);
return item;
};
}
PS :如果您有很多联系人,这可能会出现一些性能问题,因为对于每个联系人项目,您将访问数据库以检索电子邮件。
还有另一种优化的方法,方法是创建一个自定义阅读器,该阅读器将返回联系人的列表(例如1000 x 1000),并创建一个处理器,使他们的电子邮件内容更加丰富。这样,您将再次为每1000个联系项目访问数据库。
在您的阅读器中,每页检索一个唯一的雇员页面列表(说您的页面长1000)。 在您的1000名员工的处理器中,您可以在一个查询中检索所有电子邮件。
然后为每个员工设置上一个查询中检索到的电子邮件。
示例可能如下:
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Integer> {
}
@Getter
class EmployeeVO {
private Long employeeId;
private String email;
EmployeeVO(Long employeeId, String email) {
this.employeeId= employeeId;
this.email = email;
}
}
public class EmployeeListReader implements ItemReader<List<Employee>> {
private final static int PAGE_SIZE = 1000;
private final EmployeeRepository employeeRepository;
private int page = 0;
public EmployeeListReader(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
public List<Employee> read() throws Exception {
Page<Employee> employees = employeeRepository.findAll(PageRequest.of(page, PAGE_SIZE));
page++;
return employees.getContent();
}
}
@Bean
EmployeeListReader reader(){
return new EmployeeListReader(this.employeeRepository);
}
@Bean
public ItemProcessor<List<Employee>, List<Employee>> settlementHeaderProcessor(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
return item -> {
List<Long> employeesIds = item.stream().map(Employee::getId).collect(Collectors.toList());
SqlParameterSource parameters = new MapSqlParameterSource("ids", employeesIds);
List<ContactVO> emails = namedParameterJdbcTemplate
.query("SELECT CE.employeeId, CE.EMAIL FROM employee_EMAIL CE WHERE ce.contact_id IN (:ids) ",
parameters,
new RowMapper<ContactVO>() {
@Override
public ContactVO mapRow(ResultSet resultSet, int i) throws SQLException {
return new ContactVO(
resultSet.getLong("EMPLOYEE_ID"),
resultSet.getString("EMAIL"));
}
});
Map<Long, List<ContactVO>> emailsByContactId = emails.stream().collect(Collectors.groupingBy(ContactVO::getContactId));
List<Employee> newEmployeesWithEmails = Collections.unmodifiableList(item);
newEmployeesWithEmails.forEach(employee -> {
employee.setEmails(emailsByContactId.get(employee.getId()).stream().map(ContactVO::getEmail).collect(Collectors.toList()));
});
return newEmployeesWithEmails;
};
}
希望这对您有帮助