1. 简介
Spring Data JPA 提供了非常实用的特性,允许我们通过简单的命名约定定义派生方法(Derived Methods),用于从数据库中读取、更新或删除数据。这大大减少了数据访问层的模板代码,提升开发效率。
本篇文章将聚焦在 Spring Data JPA 中如何定义和使用派生的删除方法(deleteBy / removeBy),并结合实际代码示例进行说明。
2. 派生 deleteBy 方法
我们以一个简单的实体类 Fruit
为例,用于表示水果店中的水果信息,包含名称和颜色:
@Entity
public class Fruit {
@Id
private long id;
private String name;
private String color;
// standard getters and setters
}
接着定义对应的 Repository 接口,继承自 JpaRepository
,并在其中定义派生删除方法:
@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {
Long deleteByName(String name);
}
如上所示,deleteByName
方法会根据名称删除记录,并返回被删除记录的数量。
我们也可以定义类似如下的方法:
List<Fruit> deleteByColor(String color);
该方法会删除指定颜色的所有水果,并返回被删除的列表。
✅ 示例测试
我们可以先准备测试数据,写入 test-fruit-data.sql
文件:
insert into fruit(id,name,color) values (1,'apple','red');
insert into fruit(id,name,color) values (2,'custard apple','green');
insert into fruit(id,name,color) values (3,'mango','yellow');
insert into fruit(id,name,color) values (4,'guava','green');
然后编写测试方法:
@Transactional
@Test
@Sql(scripts = { "/test-fruit-data.sql" })
public void givenFruits_WhenDeletedByColor_ThenDeletedFruitsShouldReturn() {
List<Fruit> fruits = fruitRepository.deleteByColor("green");
assertEquals("number of fruits are not matching", 2, fruits.size());
fruits.forEach(fruit -> assertEquals("It's not a green fruit", "green", fruit.getColor()));
}
⚠️ 注意:删除操作必须加上 @Transactional
注解,否则会抛异常。
另一个测试方法用于验证返回值为 Long
的情况:
@Transactional
@Test
@Sql(scripts = { "/test-fruit-data.sql" })
public void givenFruits_WhenDeletedByName_ThenDeletedFruitCountShouldReturn() {
Long deletedFruitCount = fruitRepository.deleteByName("apple");
assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue());
}
3. 派生 removeBy 方法
除了 deleteBy
,Spring Data JPA 也支持使用 removeBy
来定义删除方法:
Long removeByName(String name);
List<Fruit> removeByColor(String color);
这两种方法在行为上是完全一致的,只是命名不同。
完整的 Repository 接口如下:
@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {
Long deleteByName(String name);
List<Fruit> deleteByColor(String color);
Long removeByName(String name);
List<Fruit> removeByColor(String color);
}
测试方法与前面类似,不再赘述。
4. 派生删除方法 vs @Query
在某些场景中,使用派生方法会导致方法名过长,或者涉及多个表的 JOIN 操作,这时候更适合使用 @Query
和 @Modifying
注解自定义删除逻辑。
例如,等价于前面派生方法的自定义删除方法可以这样写:
@Modifying
@Query("delete from Fruit f where f.name=:name or f.color=:color")
List<Integer> deleteFruits(@Param("name") String name, @Param("color") String color);
✅ 对比说明:
特性 | deleteBy / removeBy | @Query + @Modifying |
---|---|---|
查询方式 | 先查后删,逐条删除 | 直接执行一条 JPQL 删除语句 |
性能 | 较低(逐条操作) | 更高效(单条 SQL) |
返回值 | 可返回被删除对象列表 | 返回受影响行数 |
灵活性 | 有限 | 支持复杂查询逻辑 |
5. 总结
本文介绍了 Spring Data JPA 中的派生删除方法(deleteBy
/ removeBy
),并通过实际代码演示了其使用方式和测试方法。同时也对比了派生方法与自定义 @Query
删除操作的异同,帮助你根据具体业务场景选择合适的方式。
✅ 推荐优先使用派生方法,简单场景下开发效率高;
❌ 对于复杂查询或性能敏感场景,建议使用 @Query
自定义 JPQL 删除语句。
完整示例代码可参考:GitHub 项目地址(示例已 mock)