Spring Boot R2DBC中POST请求自动生成实体ID的方法求助
问题描述
我开发了一个Spring Boot/R2DBC应用,相关代码及遇到的问题如下:
控制器代码
@PostMapping("/add") public ResponseEntity<String> create(@RequestBody NotificationEntity e) { notificationDAO.save(e).subscribe(); return new ResponseEntity<>(HttpStatus.OK); }
Repository代码
@Repository public interface NotificationDAO extends ReactiveCrudRepository<NotificationEntity, Long> { }
实体类代码
@Data @ToString @Table(name = "notification") public class NotificationEntity { @Column @Id private Long id; @Column(value = "content_pl") private String contentPL; @Column(value = "content_en") private String contentEN; @Column(value = "event_date") private LocalDateTime eventDate; @Column private LocalDateTime seen; @Column(value = "application_id") private Integer applicationId; @Column(value = "recipient_id") private Integer recipientId; @Column(value = "type_id") private Integer typeId; @Column(value = "document_id") private Integer documentId; @Column(value = "kom_id") private Integer komId; @Column(value = "koz_id") private Integer kozId; @Column(value = "kof_id") private Integer kofId; @Column(value = "control_id") private Integer controlId; }
PostgreSQL表结构
CREATE TABLE public.notification ( id int8 NOT NULL, content_en text NULL, content_pl text NULL, event_date timestamp NULL, seen timestamp NULL, application_id int8 NULL, recipient_id int8 NULL, type_id int8 NULL, document_id int8 NULL, kom_id int8 NULL, koz_id int8 NULL, kof_id int8 NULL, control_id int8 NULL, CONSTRAINT notification_pkey PRIMARY KEY (id), CONSTRAINT fk3gh0fu4xhghdgd62lm6mljcaf FOREIGN KEY (kom_id) REFERENCES public.merit_evaluation_card(id), CONSTRAINT fk_control_id FOREIGN KEY (control_id) REFERENCES public.application_control(id), CONSTRAINT fk_kof_id FOREIGN KEY (kof_id) REFERENCES public.formal_evaluation_card(id), CONSTRAINT fk_kom_id FOREIGN KEY (kom_id) REFERENCES public.merit_evaluation_card(id), CONSTRAINT fk_koz_id FOREIGN KEY (koz_id) REFERENCES public.merit_team_evaluation_card(id), CONSTRAINT fkdolhc4dbxvvovwo0924ifbrxn FOREIGN KEY (koz_id) REFERENCES public.merit_team_evaluation_card(id), CONSTRAINT fkigjeg33g1pae9aqliuepdxnpy FOREIGN KEY (document_id) REFERENCES public."document"(id), CONSTRAINT fkk8h5styb6x923o4kkokn5k1a7 FOREIGN KEY (application_id) REFERENCES public.application(id), CONSTRAINT fkl7oja3n6j1vkasuqmux4isnk8 FOREIGN KEY (type_id) REFERENCES public.metrics_type(id), CONSTRAINT fkmlumq0ssiy6k7cklmg337k03a FOREIGN KEY (kof_id) REFERENCES public.formal_evaluation_card(id), CONSTRAINT fkmmav4veuakqbfiuctechf7qx4 FOREIGN KEY (recipient_id) REFERENCES public.app_user(id) ); CREATE INDEX notification_application_id_idx ON public.notification USING btree (application_id); CREATE INDEX notification_control_id_idx ON public.notification USING btree (control_id); CREATE INDEX notification_document_id_idx ON public.notification USING btree (document_id); CREATE INDEX notification_kof_id_idx ON public.notification USING btree (kof_id); CREATE INDEX notification_kom_id_idx ON public.notification USING btree (kom_id); CREATE INDEX notification_koz_id_idx ON public.notification USING btree (koz_id); CREATE INDEX notification_recipient_id_idx ON public.notification USING btree (recipient_id); CREATE INDEX notification_type_id_idx ON public.notification USING btree (type_id);
触发的错误
当向/api/add接口POST不含id字段的JSON数据时:
{ "contentPL": "Wnifgh", "contentEN": "Apfgh", "eventDate": "2018-04-27T17:39:18.622", "seen": "2018-05-02T08:46:51.892", "applicationId": 7388, "recipientId": 1, "typeId": 2, "documentId": null, "komId": null, "kozId": null, "kofId": null, "controlId": null }
抛出以下错误:
Caused by: io.r2dbc.postgresql.ExceptionFactory$PostgresqlDataIntegrityViolationException: null value in column "id" of relation "notification" violates not-null constraint
之前在JPA中可以用@GeneratedValue实现自动生成ID,请问在R2DBC中怎么实现相同效果?
解决方案
要在R2DBC中实现自动生成ID,需要同时修改数据库表结构和实体类注解,步骤如下:
1. 修改PostgreSQL表结构,设置ID自增
PostgreSQL 10+推荐使用标准的GENERATED AS IDENTITY语法实现自增主键,执行以下SQL修改现有表:
ALTER TABLE public.notification ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY;
如果是新建表,可直接将id字段定义为:
id int8 GENERATED ALWAYS AS IDENTITY NOT NULL,
2. 修改实体类,添加自动生成ID注解
在R2DBC中,需给@Id字段添加@GeneratedValue注解并指定策略,修改实体类的id字段:
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
这里的GenerationType.IDENTITY与数据库的自增策略匹配,R2DBC会自动将数据库生成的ID回填到实体对象中。
3. 优化控制器代码(可选但推荐)
原控制器直接调用subscribe()会忽略保存过程中的错误,建议改为返回Mono,让Spring WebFlux处理异步流程并捕获异常:
@PostMapping("/add") public Mono<ResponseEntity<String>> create(@RequestBody NotificationEntity e) { return notificationDAO.save(e) .map(saved -> new ResponseEntity<>("创建成功", HttpStatus.OK)) .onErrorResume(ex -> Mono.just(new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST))); }
完成以上修改后,POST不含id的JSON数据时,数据库会自动生成ID值,不会再触发非空约束错误。
内容的提问来源于stack exchange,提问作者mtmx
相关产品推荐
相关产品推荐

