Spring Boot 3+Batch 5:JdbcCursorItemReader读取日期字段为null问题
Spring Batch 5中JdbcCursorItemReader无法读取LocalDateTime字段的解决方案
问题原因
JPA Repository依赖ORM框架(如Hibernate)的映射机制,会自动识别@Column注解并完成Oracle TIMESTAMP(6)到LocalDateTime的类型转换。但JdbcCursorItemReader默认使用的BeanPropertyRowMapper是基于JDBC原生ResultSet做字段映射,不会识别JPA的注解,也无法自动处理Oracle TIMESTAMP类型到LocalDateTime的转换,导致该字段读取后为null,而其他基础类型字段不受影响。
解决方案
方案1:自定义RowMapper手动映射
直接实现RowMapper接口,手动处理日期字段的类型转换,这是最直接可靠的方式:
public class EmployeeRowMapper implements RowMapper<Employee> { @Override public Employee mapRow(ResultSet rs, int rowNum) throws SQLException { Employee employee = new Employee(); // 映射其他基础字段 employee.setId(rs.getLong("ID")); employee.setName(rs.getString("NAME")); // 处理CREATE_DATE_TIME字段:将ResultSet中的Timestamp转为LocalDateTime Timestamp createTime = rs.getTimestamp("CREATE_DATE_TIME"); if (createTime != null) { employee.setCreateDateTime(createTime.toLocalDateTime()); } // 映射其他字段... return employee; } }
在配置JdbcCursorItemReader时指定自定义RowMapper:
@Bean public JdbcCursorItemReader<Employee> employeeReader(DataSource dataSource) { return new JdbcCursorItemReaderBuilder<Employee>() .dataSource(dataSource) .sql("select * from EMPLOYEE") .rowMapper(new EmployeeRowMapper()) .build(); }
方案2:扩展BeanPropertyRowMapper处理日期转换
如果不想完全自定义RowMapper,可以扩展BeanPropertyRowMapper,重写字段值获取逻辑,针对LocalDateTime类型做特殊处理:
@Bean public JdbcCursorItemReader<Employee> employeeReader(DataSource dataSource) { BeanPropertyRowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class) { @Override protected Object getValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException { // 仅对LocalDateTime类型字段做转换 if (LocalDateTime.class.equals(pd.getPropertyType())) { Timestamp timestamp = rs.getTimestamp(index); return timestamp != null ? timestamp.toLocalDateTime() : null; } return super.getValue(rs, index, pd); } }; return new JdbcCursorItemReaderBuilder<Employee>() .dataSource(dataSource) .sql("select * from EMPLOYEE") .rowMapper(rowMapper) .build(); }
方案3:全局注册JDBC类型转换器
通过配置Spring的类型转换机制,让JDBC模板自动处理TIMESTAMP到LocalDateTime的转换:
@Configuration public class JdbcConversionConfig { @Bean public CustomConversions jdbcCustomConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new Converter<Timestamp, LocalDateTime>() { @Override public LocalDateTime convert(Timestamp source) { return source != null ? source.toLocalDateTime() : null; } }); return new CustomConversions(converters); } }
验证要点
- 确认数据库中
CREATE_DATE_TIME字段存在非null的数据 - 检查SQL语句是否包含该字段(使用
select *无需额外确认,若指定字段需确保包含) - 测试Spring Batch的读取流程,确认createDateTime字段已正常赋值
内容的提问来源于stack exchange,提问作者Manu
相关产品推荐
相关产品推荐

