Spring Boot存BitPay数据到PostgreSQL时timestamp为null问题
问题原因
- timestamp字段存库为null:BitPay接口返回的原始JSON中不存在timestamp字段,RestTemplate反序列化时不会自动给该字段赋值,你也没有手动给该字段设值,最终写入数据库就是null。
- 手动创建EntityManager报错:Spring Boot引入spring-boot-starter-data-jpa后,已经自动完成了EntityManager、EntityManagerFactory的容器化配置,你手动调用
Persistence.createEntityManagerFactory是原生JPA的独立使用方式,脱离了Spring容器管理,才会报找不到持久化提供者的错误,完全不需要手动配置persistence.xml,也不需要自行实例化EntityManager相关对象。
修复方案
1. 补全实体类方法
你的BitPayRates实体类只声明了字段,没有写全各字段的getter、setter方法,Jackson反序列化、JPA操作数据都依赖这些方法访问私有字段,先补全所有字段的getter/setter,同时修正toString方法把timestamp字段加入输出,方便调试。
// 补全所有字段的getter、setter,以下为timestamp字段示例 public LocalDateTime getTimestamp() { return timestamp; } public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; } // id、code、name、rate字段的getter/setter按相同规则补全即可
2. 拉取接口数据后手动赋值时间戳
删掉配置类里注释掉的手动创建EntityManager的无效代码,拿到接口返回的汇率列表后,遍历每条记录给timestamp字段赋值当前时间,再执行存库操作。
修改后的CommandLineRunner代码如下:
@Bean CommandLineRunner commandLineRunner(BitPayRatesRepo bitPayRatesRepo) { return args -> { String url = "https://bitpay.com/api/rates"; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<List<BitPayRates>> postEntity = restTemplate.exchange( url, HttpMethod.GET, null, new ParameterizedTypeReference<>() {} ); List<BitPayRates> results = postEntity.getBody(); // 统一给本次拉取的所有数据赋值抓取时间 LocalDateTime fetchTime = LocalDateTime.now(); results.forEach(rate -> rate.setTimestamp(fetchTime)); bitPayRatesRepo.saveAll(results); System.out.println(results); }; }
3. 替换timestamp为主键的注意事项
后续你要把timestamp改为主键时,注意两个问题:
- 移除原有id字段上的
@Id、序列生成器相关注解,将@Id注解加在timestamp字段上 - LocalDateTime的精度为毫秒级,如果你的接口拉取频率较高,同一毫秒下可能有多条记录,会出现主键冲突问题。建议改用精度更高的
Instant类型,或者采用timestamp + code的联合主键,避免冲突。
可选优化
- 当前控制器返回结果嵌套了两层List,没有实际意义,可以去掉服务层的
Collections.singletonList包装,直接返回查询到的汇率列表即可,简化接口结构。 - 不要在方法内部手动new RestTemplate,建议将其注册为Spring容器管理的Bean,方便后续统一配置连接超时、消息转换器等参数。
内容的提问来源于stack exchange,提问作者Alex_Pap
相关产品推荐
相关产品推荐

