CrudRepository

public interface CrudRepository<T, ID> extends Repository<T, ID> {
    
    <S extends T> S save(S entity);

    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAllById(Iterable<? extends ID> ids);

    void deleteAll(Iterable<? extends T> entities);

    void deleteAll();
}

看完后的一些疑惑:

  1. 为什么要让S extends T,操作S,而不是直接操作T?
    答:这种设计的目的是为了提供更大的灵活性和可扩展性。使用 <S extends T> 表示保存的实体可以是 T 类型的任何子类型,这样在调用 save() 方法时可以传入更具体的子类型对象,而不仅限于 T 类型本身。这样做的好处是可以支持多态性,允许在运行时保存具体子类型的对象,而不仅仅是 T 类型。
    举例:
    假设有一个 Person 类和一个 Employee 类,其中 Employee 是 Person 的子类,如果 save() 方法只接受 T 类型的对象,那么在保存 Employee 类型的对象时将不允许传入。但是通过使用 <S extends T> S save(S entity) 的泛型约束,可以传入 Employee 类型的对象进行保存。
public class Person { ... }

public class Employee extends Person { ... }

Employee employee = new Employee();
repository.save(employee);
  1. 为什么返回类型是Iterable,而不是List或者Set之类的?
    答:使用 Iterable 和 Iterator 接口作为返回类型可以适应不同类型的集合,包括 List、Set、Collection 等。List 和 Set 都实现了 Iterable 接口。 这样设计的好处是,调用方可以根据自己的需求选择将结果集转换为不同的集合类型或直接使用迭代器进行遍历,而不会对调用方强加特定的集合类型。
  2. 为什么返回类型是Optional,而不是 Iterable?
    答:Optional<T> findById(ID id) 方法会返回一个 Optional 实例,该实例可能包含找到的对象或者为空。使用 Optional 的好处是,调用方可以在获取结果之前检查返回的 Optional 实例是否包含非空值,从而避免出现空指针异常。
    如果数据存储库中没有任何对象,返回类型为Iterable的将返回一个空的迭代器。即使集合为空,也不会引发空指针异常。
  3. <? extends T><S extends T> 的区别?
    答:<? extends T> 通常用于方法参数或集合的声明,表示集合中的元素类型未知,但可以是T 类型或其子类型。这样做是为了使方法更具灵活性,可以接受不同类型的集合。通配符 <? extends T> 不能用于写入数据,只能用于读取数据。
    因为当使用 <? extends T> 作为类型限定时,编译器无法确定具体的类型,只知道它是 T 或 T 的子类型。因此,编译器不允许向这种类型的集合中添加元素,因为无法确保添加的元素是否与实际类型兼容。
    <S extends T> 用于在定义泛型类或泛型方法时指定类型参数的范围。它限制了类型参数的上界,确保类型参数必须是 T 类型或其子类型。这样做是为了在泛型类或泛型方法内部可以使用 T或其子类型的特定方法和属性。
    综上所述,<? extends T> 是用于限制集合的类型范围,<S extends T>而是用于定义泛型类或泛型方法的类型参数范围。
List<? extends Fruit> fruits = new ArrayList<Apple>();
fruits.add(new Apple());  // 编译错误
List<T> list = new ArrayList<>();
list.add(new Apple());  // 正确
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Spring Data JPA 中,CrudRepository 是一个常用的接口,用于定义数据库的增删改查操作。如果你想在这些操作执行前或执行后添加一些额外的逻辑,可以使用 SQL 拦截器来实现。 下面是一个示例,展示如何在 CrudRepository 中使用 SQL 拦截器: 1. 创建一个实现了 `org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean` 的工厂类,用于创建自定义的 JpaRepository 实例。 ```java import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; import org.springframework.data.repository.core.support.RepositoryFactorySupport; import javax.persistence.EntityManager; public class CustomJpaRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID> extends JpaRepositoryFactoryBean<T, S, ID> { public CustomJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) { super(repositoryInterface); } @Override protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { return new CustomJpaRepositoryFactory(entityManager); } } ``` 2. 创建一个实现了 `org.springframework.data.jpa.repository.support.JpaRepositoryFactory` 的工厂类,继承自默认的 JpaRepositoryFactory 类,并重写 `getQueryLookupStrategy` 方法,在其中返回一个自定义的查询策略。 ```java import org.springframework.data.jpa.provider.PersistenceProvider; import org.springframework.data.jpa.provider.QueryExtractor; import org.springframework.data.jpa.repository.query.EscapeCharacter; import org.springframework.data.jpa.repository.support.JpaRepositoryFactory; import org.springframework.data.repository.core.RepositoryMetadata; import javax.persistence.EntityManager; public class CustomJpaRepositoryFactory extends JpaRepositoryFactory { public CustomJpaRepositoryFactory(EntityManager entityManager) { super(entityManager); } @Override protected QueryExtractor getQueryExtractor() { return new CustomQueryExtractor(); } private static class CustomQueryExtractor implements QueryExtractor { private final EscapeCharacter escapeCharacter; private final PersistenceProvider persistenceProvider; public CustomQueryExtractor() { this.escapeCharacter = EscapeCharacter.DEFAULT; this.persistenceProvider = PersistenceProvider.fromEntityManager(getEntityManager()); } @Override public String extractQueryString(javax.persistence.Query query) { // 在这里可以添加拦截器逻辑 String queryString = persistenceProvider.extractQueryString(query); // 添加你的拦截器逻辑 // ... return queryString; } @Override public String extractCountQuery(javax.persistence.Query query) { return persistenceProvider.extractCountQuery(query); } } } ``` 3. 创建一个继承于 CrudRepository 的接口,并使用 `@EnableJpaRepositories` 注解指定自定义的 RepositoryFactoryBean 类。 ```java import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @EnableJpaRepositories(repositoryFactoryBeanClass = CustomJpaRepositoryFactoryBean.class) public interface UserRepository extends JpaRepository<User, Long> { } ``` 通过以上步骤,你可以在 `CustomQueryExtractor` 类的 `extractQueryString` 方法中添加拦截器逻辑,实现自定义的 SQL 拦截器。在这个方法中,你可以获取到要执行的 SQL 语句,并进行相应的处理。 请注意,以上示例仅提供了一个基本的框架,你可以根据自己的需求进行扩展和定制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值