SpringBoot+Hibernate Repository的简单使用与进阶

一、简单使用

       CrudRepository接口提供了简单的增删改查,只要如下,写一个接口继承,就可以直接使用。

public interface UserDao extends CrudRepository<User,Integer> {
}

//直接调用接口
User user = userDao.findById(2).get();

       类似还有PagingAndSortingRepository提供简单的分页与排序实现,JpaRepository提供进一步接口等,可以参考:Spring Boot学习笔记(三)Repository的使用

       到这里其实只使用Spring而初次接触Spring-JPA的话,其实就已经有疑问了:为什么这里只有一个interface继承,却可以直接使用接口,具体实现跑哪里去了?

二、原理

       具体原理可以参见spring-data-jpa原理探秘(1)-运行环境创建及加载Repository接口,简单来讲,spring-data-jpa利用cg-lib,在需要注入一个实现了Repository接口的派生接口时,都会尝试实现一个实例创建Bean注入进去。如例中的UserDao,派生自CrudRepository–>Repository,所以在注入时,会自动实现一个实例创建Bean(由工厂类来生成,该工厂类可自己实现,默认实现类为SimpleJpaRepository)注入。

       有看得仔细的会注意到,所有派生自Repository的接口,那应该包括CrudRepository啊!是的,也包括这个接口,所以又专门写了一个注解@NoRepositoryBean,来标注不需要这种操作的接口,看源码的话会发现CrudRepository是添加了这个注解的。

三、进阶一——自定义简单函数

       spring-data-jpa支持自定义简单函数,只要在interface中直接声明函数就可以了,Respository会根据函数名,自动生成sql,如:

public interface UserDao extends CrudRepository<User,Integer> {
    List<User> findByName(String name);
}

//直接使用,无需实现函数体
List<User> list = userDao.findByName("test");
//可以查看日志,生成的sql,类似:
//select * from user where name=?

       而且还支持findByNameAndValue/findByNameLike等复杂逻辑,具体支持的规则及生成的SQL参见:官方文档:Spring-data-jpa Query Creation

四、进阶二——自定义函数实现

       上面实现的是按Spring-data-jpa定义的规则生成函数,如果需要自己定义复杂点的实现,也提供了一种方式

  • 首先简单定义一个CustomizedUserRepository接口以及实现CustomizedUserRepositoryImpl,除了名称上,实现的名字必须是接口名+Impl外,没有其他强制规则
  • 让上例中的UserDao,同时继承Repository

       就是这么简单,剩余的事情,spring-data-jpa会帮你做,也就是说在二、原理 中提到的自动生成实例并注入时,会将你自定义的实现也合并进去。具体代码如下:

public interface CustomizedUserRepository {
    User getUserByName();
}

public class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
    @PersistenceContext
    private EntityManager em;
    @Override
    public User getUserByName() {
        return em.find(User.class,2);
    }
}
public interface UserDao extends CrudRepository<User,Integer>,CustomizedUserRepository {
}

//直接使用
User user = userDao.getUserByName();

       更详细的文档参见官方文档 4.6.1. Customizing Individual Repositories

五、进阶三——自定义Repository基类

       虽然Spring-data-jpa提供了详细且方便的实现,但我们有时还是会需要自定义一些公共的函数,Spring-data-jpa也提供了实现的方法:

  • 自定义一个基础接口BaseRepository及实现类BaseRepositoryImpl,实现自己的公共函数
  • 添加自定义Repository类配置:@EnableJpaRepositories(repositoryBaseClass = BaseRepositoryImpl.class)

       实现虽然很简单,但也碰到了一个坑,因为官方文档上并没有提到使用接口,接口只是为了后续自己的interface使用方便,具体看代码:

//下面再解释为什么要加@NoRepositoryBean
@NoRepositoryBean
public interface BaseRepository<T> {
    public List<T> findBySql(String sql, Object... values);
}


public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T> {
    private final EntityManager entityManager;

    public BaseRepositoryImpl(JpaEntityInformation entityInformation,
                              EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    private Session getSession(){
        return entityManager.unwrap(Session.class);
    }

    private NativeQuery createSqlQuery(String sql , Object... values){
        NativeQuery query = getSession().createNativeQuery(sql);
        for(int i = 0;i < values.length;++i){
            query.setParameter(i + 1,values[i]);
        }
        return query;

    }

    public List<T> findBySql(String sql, Object... values){
        return createSqlQuery(sql,values).addEntity(getDomainClass()).list();
    }
}

public interface UserDao extends CrudRepository<User,Integer>, BaseRepository<User> {
}

@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = BaseRepositoryImpl.class)
public class SpringbootdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootdemoApplication.class, args);
    }
}

//直接使用
List<User> list = userDao.findBySql("select * from user");

       这里的坑就是为什么BaseRepository要用@NoRepositoryBean这个注解,因为BaseRepository只是一个简单的接口,明明什么都没做,为什么要特殊处理呢?其实做了一个实验就会知道为什么:如果将BaseRepository重新命名为OtherRepository,但BaseRepositoryImpl保持不变,则不加@NoRepositoryBean注解也是可以的。再联想下第四条里的内容,就可以知道,因为我们这里使用的接口+实现且实现名=接口名+Impl的命名规则,以及UserDao的继承方式,和四、进阶二——自定义函数实现 中的处理都是完全一样的,所以会被误处理,这时,加上@NoRepositoryBean注解,就是用来取消这个错误处理的!
       所以SpringBoot有很多自动配置,确实可以减少大量工作,但用不好的话,很难调试及发现。
       官方文档这部分的内容较少,参见:4.6.2. Customize the Base Repository

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中使用Elasticsearch进行分页查询,可以通过继承ElasticsearchRepository接口来实现。首先,确保已经引入了spring-boot-starter-data-elasticsearch依赖,并配置好相关的Elasticsearch连接信息。 接下来,创建一个继承自ElasticsearchRepository的接口,并指定实体类和主键类型。在该接口中,可以使用Spring Data Elasticsearch提供的方法进行分页查询,其中包括searchSimilar方法。 下面是一个示例代码: ```java import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.annotations.Query; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; public interface UserRepository extends ElasticsearchRepository<User, String> { @Query("{\"bool\" : {\"must\" : {\"term\" : {\"name\" : \"?0\"}}}}") Page<User> searchSimilar(String name, Pageable pageable); } ``` 在上述示例中,User是实体类,String是主键类型。searchSimilar方法使用了自定义的查询语句,并通过Pageable参数实现了分页查询。 使用该接口进行分页查询的示例代码如下: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserRepository userRepository; public Page<User> searchSimilarUsers(String name, int page, int size) { Pageable pageable = PageRequest.of(page, size); return userRepository.searchSimilar(name, pageable); } } ``` 在上述示例中,UserService类使用了UserRepository接口进行分页查询,通过调用searchSimilar方法实现了根据name字段进行相似查询,并指定了页码和每页大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值