# 3.2.3 声明 JPA repository

在存储库的 JDBC 版本中，显式地声明了希望 repository 提供的方法。但是使用 Spring Data，扩展 CrudRepository 接口。例如，这是一个新的 IngredientRepository 接口：

```java
package tacos.data;
​
import org.springframework.data.repository.CrudRepository;
import tacos.Ingredient;
​
public interface IngredientRepository extends CrudRepository<Ingredient, String> {
}
```

CrudRepository 为 CRUD（创建、读取、更新、删除）操作声明了十几个方法。注意，它是参数化的，第一个参数是存储库要持久化的实体类型，第二个参数是实体 id 属性的类型。对于 IngredientRepository，参数应该是 Ingredient 和 String 类型。

也可以这样定义 TacoRepository：

```java
package tacos.data;
​
import org.springframework.data.repository.CrudRepository;
import tacos.Taco;
​
public interface TacoRepository extends CrudRepository<Taco, Long> {
}
```

IngredientRepository 和 TacoRepository 之间唯一显著的区别是对于 CrudRepository 的参数不同。在这里，它们被设置为 Taco 和 Long 去指定 Taco 实体（及其 id 类型）作为这个 respository 接口的持久化单元。最后，同样的更改可以应用到 OrderRepository：

```java
package tacos.data;
​
import org.springframework.data.repository.CrudRepository;
import tacos.Order;
​
public interface OrderRepository extends CrudRepository<Order, Long> {
}
```

现在有了这三个 repository，可能认为需要为这三个 repository 编写实现，还包括每种实现的十几个方法。但这就是 Spring Data JPA 优秀的地方 —— 不需要编写实现！当应用程序启动时，Spring Data JPA 会动态地自动生成一个实现。这意味着 repository 可以从一开始就使用。只需将它们注入到控制器中，就像在基于 JDBC 的实现中所做的那样。

CrudRepository 提供的方法非常适合用于实体的通用持久化。但是如果有一些基本持久化之外的需求呢？让我们看看如何自定义 repository 来执行域特有的查询。
