Groovy与JPA导致Spring Boot CrudRepository无法执行插入的问题
解决Spring Data JPA save()仅执行更新无法插入多条数据的问题
这个问题我之前也碰到过!核心原因很明确——你手动给GroceryItem实例设置了ID值,导致Spring Data JPA的save()方法误判这是一个已存在的实体,从而执行更新而非插入操作。
为什么会这样?
Spring Data JPA的save()方法逻辑是:
- 如果实体的ID为
null(或者对应数据库的空值,比如数值类型的0),就会执行插入(persist)操作 - 如果实体ID有具体值,JPA会先查询数据库中是否存在该ID的记录:存在则更新(
merge),不存在则抛出异常(取决于你的配置)
你用了GenerationType.IDENTITY策略,意味着ID是由数据库自动生成的,这时候手动指定ID完全违背了这个策略的设计意图,自然会出问题。
具体修改方案
1. 改掉手动传ID的代码
创建新的GroceryItem时,不要再传入ID参数:
// 原来的错误写法 GroceryItem olives = new GroceryItem(1L, '123456', 'Olives', 6) // 修改后的正确写法 GroceryItem olives = new GroceryItem('Olives', 6)
2. 调整实体的构造函数配置
你给GroceryItem加了@TupleConstructor(includeSuperProperties = true),这个注解会生成包含父类BaseEntity中id属性的构造函数,但我们创建新实体时不需要传入ID,所以有两种调整方式:
方式一:移除父类属性的构造参数
直接去掉includeSuperProperties = true,让构造函数只包含当前类的属性:
@Canonical @TupleConstructor // 移除includeSuperProperties参数 @ToString(includeSuperProperties = true) @Entity(name = 'grocery_items') @AttributeOverrides([ @AttributeOverride(name = "id", column=@Column(name="grocery_item_id")) ]) class GroceryItem extends BaseEntity { @Column(name = 'grocery_item_name') @NotNull @Valid String name @Column(name = 'grocery_item_qty') @NotNull Integer quantity }
方式二:手动添加无ID的构造函数
如果需要保留原有构造函数,额外加一个只接收name和quantity的构造函数:
@Canonical @TupleConstructor(includeSuperProperties = true) @ToString(includeSuperProperties = true) @Entity(name = 'grocery_items') @AttributeOverrides([ @AttributeOverride(name = "id", column=@Column(name="grocery_item_id")) ]) class GroceryItem extends BaseEntity { @Column(name = 'grocery_item_name') @NotNull @Valid String name @Column(name = 'grocery_item_qty') @NotNull Integer quantity // 手动添加用于创建新实体的构造函数 GroceryItem(String name, Integer quantity) { this.name = name this.quantity = quantity } }
3. 验证修改效果
修改后再运行你的代码,save()方法就会正确识别新实体并执行插入,你会看到控制台输出两条记录的结果。
内容的提问来源于stack exchange,提问作者smeeb
相关产品推荐
相关产品推荐

