SpringBoot使用JPA来做数据查询

Spring-Data-JPA在做数据存储方面真的很方便,它的目的就是写更少的代码,更多的事情,但是也有其力有未逮或者说处理起来比较闹心的地方。

  1.先来感受一下使用JPA做数据查询时,代码的简化程度


@CacheConfig(cacheNames = "news")
public interface NewsRepository extends PagingAndSortingRepository<NewsEntity, Long> {
    @Cacheable
    NewsEntity findOne(Long id);

    @Cacheable
    NewsEntity findTop1ByOriginId(String originId);

    @Transactional
    long deleteByOriginId(String originId);           
    
    Page<NewsEntity> findDistinctByTitleStartingWithAndSimilarIdIsNullOrderByPubDateDesc(String title, Pageable pageable); 
}

单表查询时,只需要根据JPA提供的规范去命名,根本不需要自己去写什么查询语句就可以。

  2.当然要自己写SQL语句也没有问题

@Query(value = "select e.* from news_detail e INNER JOIN news_info n  on e.news_id = n.id where n.pub_date >= ?1", nativeQuery = true)
List<Object> listBypubDateWithEntityDetail(String pubDate);

@Query(value = "select n.id,GROUP_CONCAT(e.ent_id) from news_info n INNER JOIN map_news_company e on e.news_id = n.id where n.pub_date>= ?1 and n.id>?2 group by n.id order by n.id limit 10000", nativeQuery = true)
List<Object[]> listBypubDateWithEnts(String pubDate, long news_id);

使用原生的SQL也可以,JPA就是这么方便,然而总有需要操心的地方——多条件分组查询。用过Hibernate和Mybatis的,在写业务逻辑的时候,拼接查询条件的时候,一定写过很多if条件不为空的判断,这就是JPA操蛋的地方。

  3.看看例子

    @Query(value = "select pub_time,count(1) as count from t_weibo where content like %:keyword% and pub_time>=:dateFrom and pub_time<=:dateTo group by pub_time", nativeQuery = true)
    List<Object[]> getWeibo(@Param("keyword") String keyword, @Param("dateFrom") Date dateFrom, @Param("dateTo") Date dateTo);

    @Query(value = "select pub_time,count(1) as count from t_weibo where content like %:keyword% and pub_time>=:dateFrom and pub_time<=:dateTo and region in ( select keyname from t_cell where  provincename=:provincename) group by pub_time", nativeQuery = true)
    List<Object[]> getWeiboByProvince(@Param("provincename") String provincename,@Param("keyword") String keyword,@Param("dateFrom") Date dateFrom, @Param("dateTo") Date dateTo);

这个例子两个方法的作用一样,条件个数不一样,这就是冗余了。

  4.如果是这样JPA被设计出来的意义是什么,jpa有一套来应对这些的措施,使用Specification这个来来完成条件拼接

User user1 = (User) userRepository.findOne(new Specification<User>() {
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                /*criteriaQuery.where(criteriaBuilder.equal(root.<String>get("name"), user.getName()),
                        criteriaBuilder.equal(root.<String>get("password"), user.getPwd()));*/
          Predicate predicate = null;
          if(user.getName!=null&&!user.getName().equal){
            if(predicate!=null){
             predicate =
criteriaBuilder.equal(root.<String>get("name"), user.getName())
                    }else{
              predicate =
criteriaBuilder.and(predicte,criteriaBuilder.equal(root.<String>get("name"), user.getName()))
                    }
                }
          if(predicate!=null){
            criteriaQuery
.where(predicate);
          }
return null; } });

核心就是使用CriteriaBuilder 进行条件拼接

  5.还有一种方式就是使用QueryDsl插件来组合Spring Data JPA使用

添加maven依赖
        <!--queryDSL-->
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
            <scope>provided</scope>
        </dependency>
 配置querydsl插件
    <build>
        <plugins>
            <!--该插件可以生成querysdl需要的查询对象,执行mvn compile即可-->
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources/java</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

此时编译(compile)一下maven项目,在这个(target/generated-sources/java)文件夹下看到对应于你建的实体类(User)的QueryDsl类(QUser)

@Entity
@Table(name = "users")
@Data
public class UserBean
{
    @Id
    @GeneratedValue
    @Column(name = "u_id")
    private Long id;
    @Column(name = "u_username")
    private String name;
    @Column(name = "u_age")
    private int age;
    @Column(name = "u_score")
    private double socre;
}

查询语句

@PersistenceContext
EntityManager entityManager;
@RequestMapping("query")
    public List<GoodEntity> list(){
        QUserBean userBean = QUserBean.userBean;
        JPAQuery<UserBean> jpaQuery = new JPAQuery<>(entityManager);
        return jpaQuery.select(userBean)
                .from(userBean)
                .where(userBean.name.eq("haha"))
                .fetch();
    }

  

posted @ 2017-12-29 15:36  释然的蛋  阅读(19843)  评论(0编辑  收藏  举报