Spring JPA执行原生INSERT查询后如何获取插入的实体及对应ID
问题原因
Spring Data JPA 中被@Modifying标记的写操作查询(INSERT/UPDATE/DELETE),默认仅支持void、int/Integer(返回受影响行数)、boolean/Boolean(返回是否有行被修改)三类返回值,不支持直接返回实体类,这是你遇到报错的根本原因。
解决方案
你可以根据自己的技术栈选择以下任意一种方案解决:
方案1:拆分插入+查询操作(全数据库兼容)
这个方案不需要修改SQL语法,兼容性最强。
- 调整Repository方法的返回值为int:
@Query(value = INSERT_USER_IN_TO_DATABASE, nativeQuery = true) @Modifying int saveNewUser(String encryptionKey, String phoneNumber, String name, String lastName, String gender, String dob);
- 在业务逻辑层先执行插入方法,判断返回值为1说明插入成功,再通过业务唯一键(比如手机号、用户ID等)查询刚插入的实体即可。注意需要在业务方法上加
@Transactional注解,保证插入和查询操作的原子性。
方案2:用数据库RETURNING语法直接返回插入结果(适配支持该语法的数据库)
如果你的数据库是PostgreSQL、MySQL 8.0+、Oracle、SQL Server等支持插入后返回行的数据库,可以直接修改SQL拿到返回实体:
- 调整原生SQL,在末尾加上对应数据库的返回行语法,示例(不同数据库语法略有差异,按需调整):
// 示例为SQL Server语法,用OUTPUT返回插入行;PostgreSQL/MySQL 8.0+直接写RETURNING *即可 String INSERT_USER_IN_TO_DATABASE = "INSERT INTO USER_MASTER " + "(" + "MOBILE_X,USER_TYPE,COUNTRYCODE,USER_N,USER_LAST_N,GENDER,DOB) " + "VALUES ( " + "EncryptByKey(Key_GUID(convert(varchar,?1)), ?2)," + "1,+91,?3,?4,?5,?6" + ")" + "OUTPUT inserted.*";
- 移除方法上的
@Modifying注解,返回值保留UserMasterEntity即可,Spring Data JPA会自动将返回的行映射为实体对象。
方案3:用@ColumnTransformer实现自动加解密,复用JPA原生save方法
你之前尝试的@ColumnTransformer本身是可行的,只是需要调整使用方式,不需要自己写原生INSERT:
- 在
UserMasterEntity的手机号字段上配置加解密规则:
@Column(name = "MOBILE_X") @ColumnTransformer( write = "EncryptByKey(Key_GUID(convert(varchar, ?1)), ?2)", read = "DecryptByKey(MOBILE_X)" ) private String mobileX;
- 实体中其他固定字段(USER_TYPE、COUNTRYCODE)可以直接设置默认值,构造实体时赋值即可。
- 直接调用JPA Repository自带的
save()方法插入实体,插入完成后会自动返回带主键的完整实体,不需要自定义插入语句。注意使用该方案需要保证操作前已经打开了对应的数据库加密密钥。
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

