文档章节

springboot学习笔记5(JPA 实现分页、排序、返回map集合)

trntaken
 trntaken
发布于 2017/06/03 11:52
字数 2039
阅读 1028
收藏 2

       在相当长的一段时间里,实现应用程序的数据访问层非常麻烦。必须编写太多的模板代码来执行简单的查询,以及执行分页。Spring  JPA旨在通过减少实际需要的工作量来显著改进数据访问层的实现。作为开发人员,您可以编写存储库接口,包括自定义查找程序方法。下面介绍  springboot集成JPA的使用:

JPA核心接口是Repository,其它所有接口都在此类的基础上进行了扩展。 下面是JPA关系图解图:

 熟悉JPA的几个API

     CurdRepository提供了增删改产方法,PagingAndSortingRepositroy增加了分页查询方法,JpaRepositroy又增加了实例查询方法。实际应用中可以有选择的继承上面接口即可。上面说过,jpa提供了封装查询数据库模板方法。下面就来一一介绍JPA给我们提供的模板方法:

CurdRepository 

         接口,提供增删改查基本的功能

@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
	
	<S extends T> S save(S entity);
	
	<S extends T> Iterable<S> save(Iterable<S> entities);

	T findOne(ID id);
	
	boolean exists(ID id);
	
	Iterable<T> findAll();

	Iterable<T> findAll(Iterable<ID> ids);
	
	long count();
	
	void delete(ID id);

	void delete(T entity);

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

	void deleteAll();
}

PagingAndSortingRepositroy

      接口 ,分页查询,和排序

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
       //分类查询
	Iterable<T> findAll(Sort sort);
       //分页查询
	Page<T> findAll(Pageable pageable);
}

JpaRepositroy

      接口,提供实例查询方法

@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable>
		extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

	List<T> findAll();
	
	List<T> findAll(Sort sort);

	List<T> findAll(Iterable<ID> ids);

	<S extends T> List<S> save(Iterable<S> entities);

	void flush();
	
	<S extends T> S saveAndFlush(S entity);

	void deleteInBatch(Iterable<T> entities);
	
	void deleteAllInBatch();

	T getOne(ID id);
         
      //实例查询
	@Override
	<S extends T> List<S> findAll(Example<S> example);

      //实例查询,分类排序
	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

SimpleRepository

      实现类,增加了事务注解,进行事务管理,这就不介绍了,讲到自定义封装基类的时候会用到,一般都不会继承使用这个类.

二、使用 

       自定义一个PersonRepository接口继承上述任何一个接口都可以。不需要在接口上加@Repository注解,也不需要写实现类,即可在service,controller层注入使用,是不是很简洁。对于一般的修改保存操作,只要直接调用JPA接口提供的方法就可以用了,这里就不在介绍了。

entity层 

      Person实体类:

@Entity
public class Person {
 
  private Integer id;  
 
  private String name;
  
  private String password;


  .....省略get set方法

}

PersonName接口

     如果只需要查询person 中的name ,可以先定义一个接口,这种方式还是比较常用的:


public interface PersonName {
              
  String getName();

}

持久层

PersonRepository 接口

     下面介绍了JPA查询方法,条件查询,list集合查询,分页查询,排序查询,sql语句查询,指定字段查询,实例查询,基本上包含了实际开发中所需要的查询方法。

//省略了注释。
public interface PersonRepository extends JpaRepository<Person, Integer> {
	
       //自定义查询,AND为jpa 关键字,相当于(where x.lastname = ?1 and x.firstname = ?2)
        jpa关键字应该都要熟悉
        Person findByNameAndPassword(String name ,String password);

        //指定字段查询,只返回name
        PersonName   findById(Integer id); 
        
         //排序查询,返回list集合
        List<Person> findByNameAndPassword(String name ,String password,Sort sort);
         
         //分页查询 查询计算元素总个数总页数,数据多的情况下,代价是昂贵的
        Page<Person> findByNameAndPassword(String name ,String password,Pageable pageable);
         //分页查询,返回的是一个片段,它只知道下一片段或者上一片段是否可用。
        Slice<Person> findByNameAndPassword(String name,Pageable pageable); 

         //sql查询。?后面数字,对应方法中参数位置。使用原生sql语句
        @Query("select p from person as p where p.name = ?1 and p.password = ?2 ",nativeQuery = true) 
        Person myfind(String name ,String password);
        
        //实例查询
        Person findByExample(Example example)
}

    说明: JPA 提供两种查询方式,一种就是直接从方法名中派生中查询(需要遵循它的规范,见下文 JPA 查询语句关键字)上面的例子就是这种方式;另一种就是手动定义查询了(使用JPA 核心类 EntityManager,下文自定义查询会介绍)。

Controller 层

@RestController public class TestController  {
	
    @Resource
    private PersonRepository personRepository;
        @GetMapping(value = "/test")
	  public String test(Integer personId){
        
       Person  p = personRepository.findByNameAndPassword("张三","123");
  	
      //排序
      List<Person> p1 = personRepository.findByNameAndPassword("张三","123",
			new Sort(Sort.Direction.ASC,"id"));
      //分页
      Page<Person> p2 = personRepository.findByNameAndPassword("张三",
				"123", new PageRequest(1,10,new Sort("id")));
      
       Person tempPerson=new Person();
       tempPerson.setId(personId));
       //通过实例查询 
       Person p3= personRepository.findByExample(Example.of(tempPerson))     
        
		return    p+"+"+ p1 "+"+p2.getTotalElements()+"+"+p3;
	}

JPA 查询语句关键字

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = 1?
Between findByStartDateBetween … where x.startDate between 1? and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> age) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame)

 自定义查询(返回map集合):

       上面的例子都是一些简单的查询,但实际开发中,我们可能会需要用到复杂的sq、连接查询或者需要查询结果只包含我们需要的字段。如果实体之间的关联关系都配置得当的话,JPA提供的方法也可以满足我们的需求。当然我们也可以自定义一个继承JPA的模板类,然后封装查询的方法:

BaseRepository

创建一个BaseRepository ,定义两个sq语句查询:

/**
 * repository 基类,封装自定义查询方法
 *
 * @author 
 * @date 2017/5/12 8:32
 * @Package com.base
 * @Version v1.0
 */
@NoRepositoryBean //该注解表示 spring 容器不会创建该对象
public interface BaseRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>,JpaRepository<T,ID> {
       
    /**
     * sql查询
     *
     * @param sql
     * @param args
     * @return
     */
    List<Map> findAllByParams(String sql, Object... args);

  /**
     * sql分页查询
     *
     * @param sql
     * @param args
     * @return
     */
    Page<Map> findPageByParams(String sql, Pageable pageable, Object... args);


}

BaseRepositoryImpl

BaseRepositoryImpl 类,实现BaseRepository 接口:

/**
 * @author 
 * @date 2017/5/12 8:32
 * @Package com.base.impl
 * @Version v1.0
 */
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {
    
    //实体管理类,对持久化实体做增删改查,自动义sq操作模板所需要的核心类
    public final EntityManager entityManager;

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Map> findAllByParms(String sql, Object... args) {
        //获取session
        Session session = (Session) entityManager.getDelegate();
        org.hibernate.Query q = session.createSQLQuery(sql);
         //查询结果转map        
        q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
        int i = 0;
        for (Object arg : args
                ) {
            q.setParameter(i++, arg);
        }
        return q.list();
    }

     @Override
     @Transactional(rollbackFor = Exception.class)
    public Page<Map> findPageByParams(String sql, Pageable pageable, Object... args) {
        Session session = (Session) entityManager.getDelegate();
        org.hibernate.Query q = session.createSQLQuery(sql);
        q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
        int i = 0;
        for (Object arg : args
                ) {
            q.setParameter(i++, arg);
        }

        List<Map> totalCount = q.list();
        q.setFirstResult(pageable.getPageSize() * (pageable.getPageNumber() - 1));
        q.setMaxResults(pageable.getPageSize());
        List<Map> pageCount = q.list();
        Page<Map> pages = new PageImpl<>(pageCount, pageable, totalCount.size());
        return pages;
    }

}

PersonRepositroy

创建一个PersonRepositroy 继承BaseRepository,就可以直接使用定义的查询方法了:


/**
 * @author 
 * @date 2017/5/12 10:07
 * @Package com.repository
 * @Version v1.0
 */
public interface PersonRepository extends BaseRepository<Person, Integer> {

}

 TestController 

@RestController public class TestController  {
	
    @Resource
    private PersonRepository personRepository;

   @GetMapping(value = "/test")
   public String test( ){
        //订单表与用户表关联,通过用户ID查询该用户的所有订单,只获取订单编号和订单详情。
       String sql="select o.no,o.detail from person as p inner join order as o on o.personid=p.id and p.id= ? "
      Integer userId=11;
      Page<Map>  orderLists = personRepository.findPageByParams(sql,new PageRequest(1,10),userId);
  
		return   orderLists;
	}
}

 

最后,在项目启动类上加一个注解,告诉springboot,我要使用JPA,请到repository包下去扫描我创建的repository 类,我的repository基类是BaseRepositoryImpl:

@EnableJpaRepositories(basePackages = {"com.repository"}, repositoryBaseClass = BaseRepositoryImpl.class)
public class MybootApplication {
 
public static void main(String[] args) {
		SpringApplication.run(MybootApplication.class, args);
	}

}

这样启动项目,就可以进行对数据库访问了。上面的例子主要是解决如何使用sq语句对数据库操作,对于其他情况,大家可以自己尝试。

© 著作权归作者所有

trntaken
粉丝 3
博文 26
码字总数 34519
作品 0
深圳
程序员
私信 提问
加载中

评论(1)

木昜不良人
入门学习,真的很不错哦,推荐
Spring Boot入门资料整理

Spring Boot 初识 SpringBoot前世今生 本文主要讲述spring boot的由来,即其它诞生的背景,初衷,现状,及对未来的展望。 Spring Boot参考指南中文版--Chapter1.Spring Boot中文文档 本节提供...

小致dad
2017/11/07
537
0
springboot 是如何帮我们省去web.xml配置的

概述 最开始使用原生的springmvc时,总是免不了有如下xml配置 但是,切换到springboot之后,web.xml之类的繁琐的配置基本上都不见了。出于好奇研究了下springboot究竟帮我们做了什么,我们可...

端吉
2018/06/23
0
0
springboot(一)入门篇

今天来整理下springboot,开发工具使用eclipse(后期会再做个idea的).主要实现的功能是 1.通过数据库的查询返回前端数据. 第二步:新建entity 第三步:新建UserMapper(需要在application.propert...

zhuyuansj
2017/10/06
0
0
springboot学习(二)——springmvc配置使用

以下内容,如有问题,烦请指出,谢谢 上一篇讲解了springboot的helloworld部分,这一篇开始讲解如何使用springboot进行实际的应用开发,基本上寻着spring应用的路子来讲,从springmvc以及web...

嘻哈开发者
2018/04/26
142
0
SpringBoot | 第三十章:Spring-data-jpa的集成和使用

前言 在前面的第九章:Mybatis-plus的集成和使用章节中,介绍了使用框架进行数据库的访问。今天,我们来简单学习下如何使用进行数据库的访问。由于本人未使用过,也是趁着写博文的机会查阅了...

oKong
2018/10/31
278
0

没有更多内容

加载失败,请刷新页面

加载更多

秒杀系统思路

业务分析 技术挑战 请求响应要快:无论成功失败,需要尽快返回给用户 架构设计   前端:静态化   站点层:限制请求数   服务层:乐观锁写缓存   数据库CAP:读写高可用,一致性,扩容...

雷开你的门
28分钟前
10
0
最全的教育行业大数据解决方案,个个针对痛点

大数据的悄然兴起也带动了教育行业的革新,移动教育、云课堂等的出现,使得教育行业再次成为了可以中长期保持高景气的行业。然而,初涉数据领域的教育行业同时也面临着相当大的难题,还需要更...

朕想上头条
32分钟前
7
0
预约模块设计分析

1.预约功能描述: 预约是小程序中常见的一种商品管理系统,商家可根据商品或服务的特性,灵活设置预约细节,为用户提供线上预约服务,如场地预约,商品预定等,实现高效经营。 预约场景: ...

鱼煎
35分钟前
5
0
阿里云日志服务构建网站实时分析大盘实战

场景分析 挖掘数据价值是当前企业级网站共同面临的问题。买买网是一个电商平台网站,每天拥有大量的用户访问和购买记录。为了引导用户直接消费,提升购买率和转化率,不同的用户类别需要推荐...

阿里云官方博客
36分钟前
5
0
TL665xF-EasyEVM开发板硬件处理器、NAND FLASH、RAM

广州创龙结合TI KeyStone系列多核架构TMS320C665x及Xilinx Artix-7系列FPGA设计的TL665xF-EasyEVM开发板是一款DSP+FPGA高速大数据采集处理平台,其底板采用沉金无铅工艺的6层板设计,适用于高...

Tronlong创龙
39分钟前
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部