Spring Boot第八章-Spring Data JPA(续)

Spring Boot第八章-Spring Data JPA(续)

                                                                          Spring Data JPA(续)

目录

1.jpa自定义sql查询

2.jpa更新

3.jpa删除

4.一些常用注解的理解

5.自定义查询简单实例:

6.JPA 关联表自定义动态查询


上一个博客介绍了Spring Data JPA,但是总感觉不够,因而加了此篇博客作为续,以后关于JPA的东西都写在这篇文章里,毕竟在实际运用中会遇到很多需要注意的地方。

 

1.jpa自定义sql查询

直接上代码:

 //自定义查询
    @Query(value = "select * from person where name=?1 and age>18",nativeQuery = true)
    List<Person> findByMyQuery(String name);

此处跟之前的@Query有区别,nativeQuery=true,这样的话就用本地的查询语句了,根据value里面的正常的sql语句进行查询,注意这里写的就是真实的表名了。而如果不是nativeQuery=true,写的是类名。

2.jpa更新

直接上代码:

 //更新操作(更新,删除的操作必须有事务,这个事务可以在这里写,也可以在service里写)
    @Transactional
    @Modifying
    @Query(value = "update Person set age=?2 where id=?1")
    int updatePersonAge(Long id,int age);

注意,我在这里加了事务,还有@Modifying,这个是必须的

3.jpa删除

直接上代码:

 @Transactional
    //删除操作
    int deleteByAge(int age);

同样的,也得加事务,这个事务也可以写在service里

4.一些常用注解的理解

@Entity和@Table的区别:

@Entity说明这个class是实体类,并且使用默认的orm规则,即class名即数据库表中表名,class字段名即表中的字段名
如果想改变这种默认的orm规则,就要使用@Table来改变class名与数据库中表名的映射规则

@Column:

改变class中字段名与db中表的字段名的映射规则

具体见以下描述:

@Entity注释指名这是一个实体Bean,@Table注释指定了Entity所要映射带数据库表,其中@Table.name()用来指定映射表的表名。
如果缺省@Table注释,系统默认采用类名作为映射表的表名。实体Bean的每个实例代表数据表中的一行数据,行中的一列对应实例中的一个属性。

@Column注释定义了将成员属性映射到关系表中的哪一列和该列的结构信息,属性如下:
1)name:映射的列名。如:映射tbl_user表的name列,可以在name属性的上面或getName方法上面加入;
2)unique:是否唯一;
3)nullable:是否允许为空;
4)length:对于字符型列,length属性指定列的最大字符长度;
5)insertable:是否允许插入;
6)updatetable:是否允许更新;
7)columnDefinition:定义建表时创建此列的DDL;
8)secondaryTable:从表名。如果此列不建在主表上(默认是主表),该属性定义该列所在从表的名字。
@Id注释指定表的主键,它可以有多种生成方式:

1)TABLE:容器指定用底层的数据表确保唯一;
2)SEQUENCE:使用数据库德SEQUENCE列莱保证唯一(Oracle数据库通过序列来生成唯一ID);
3)IDENTITY:使用数据库的IDENTITY列莱保证唯一;
4)AUTO:由容器挑选一个合适的方式来保证唯一;
5)NONE:容器不负责主键的生成,由程序来完成。

@GeneratedValue注释定义了标识字段生成方式。

@Temporal注释用来指定java.util.Date或java.util.Calender属性与数据库类型date、time或timestamp中的那一种类型进行映射。

@Temporal(value=TemporalType.TIME)

实例如下:

package com.just.springjpa.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 1.@Entity说明这个class是实体类,并且使用默认的orm规则,即class名即数据库表中表名,class字段名即表中的字段名
 * 如果想改变这种默认的orm规则,就要使用@Table来改变class名与数据库中表名的映射规则,
 * 2.@Column来改变class中字段名与db中表的字段名的映射规则
 */
@Entity
@Table(name = "t_student")
public class Student {
    @Id
    @GeneratedValue
    private Long id;
    /**
     * varchar类型长度50
     */
    @Column(name = "s_name",length = 50)
    private String name;
    /**
     * 不允许为空
     */
    @Column(name="s_age",nullable = false)
    private Integer age;
    /**
     * columnDefinition 创建表时,该字段创建的SQL语句,更灵活的创建表
     */
    @Column(name="created_time",columnDefinition = "datetime COMMENT '创建时间' ")
    private Date createdTime;
    /**
     * 精度12,小数点后2位
     */
    @Column(name="money",precision = 12,scale = 2)
    private BigDecimal money;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreateTime(Date createdTime) {
        this.createdTime = createdTime;
    }
}

具体效果可以看下自己生成的表:

Spring Boot第八章-Spring Data JPA(续)

2018-08-07       


5.自定义查询简单实例:

还是用到了上一篇博客的Specification,简化版,提供的是一种直接简单用的思路,java8的函数式编程风格

1.repository要继承JpaSpecificationExecutor

public interface PersonRepository extends JpaRepository<Person, Long>  ,JpaSpecificationExecutor<Person> {
}

来看看JpaSpecificationExecutor源码,我们可以用里面的一些方法查询,其中还有分页的查询:

/*
 * Copyright 2008-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.jpa.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

/**
 * Interface to allow execution of {@link Specification}s based on the JPA criteria API.
 * 
 * @author Oliver Gierke
 */
public interface JpaSpecificationExecutor<T> {

	/**
	 * Returns a single entity matching the given {@link Specification}.
	 * 
	 * @param spec
	 * @return
	 */
	T findOne(Specification<T> spec);

	/**
	 * Returns all entities matching the given {@link Specification}.
	 * 
	 * @param spec
	 * @return
	 */
	List<T> findAll(Specification<T> spec);

	/**
	 * Returns a {@link Page} of entities matching the given {@link Specification}.
	 * 
	 * @param spec
	 * @param pageable
	 * @return
	 */
	Page<T> findAll(Specification<T> spec, Pageable pageable);

	/**
	 * Returns all entities matching the given {@link Specification} and {@link Sort}.
	 * 
	 * @param spec
	 * @param sort
	 * @return
	 */
	List<T> findAll(Specification<T> spec, Sort sort);

	/**
	 * Returns the number of instances that the given {@link Specification} will return.
	 * 
	 * @param spec the {@link Specification} to count instances for
	 * @return the number of instances
	 */
	long count(Specification<T> spec);
}

2.在service方法里面使用,我是用的Page<T> findAll(Specification<T> spec, Pageable pageable);,自定义+分页

  @Override
    public Page<Person> findDynamically(Person person, Pageable pageable,Map<String,Object> otherParams) {
        return personRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            //如果是查名字,按照名称模糊查询
            if(StringUtils.isNotBlank(person.getNickName())){
               predicates.add(criteriaBuilder.like(root.get("nickName"),"%"+person.getNickName()+"%"));
            }
            //所在城市,精确搜索
            if(StringUtils.isNotBlank(person.getCity())){
                predicates.add(criteriaBuilder.equal(root.get("city"),person.getCity()));
            }
            //审核状态,精确搜索
            if(person.getAuditStatus()!=null){
                predicates.add(criteriaBuilder.equal(root.get("auditStatus"),person.getAuditStatus()));
            }
            //比较日期
            if(otherParams.containsKey("afterEndTime")){
               predicates.add(criteriaBuilder.greaterThan(root.get("authEndTime"),new Date()));
            }
            if(otherParams.containsKey("beforeEndTime")){
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("authEndTime"),new Date()));
            }
            //比较年龄范围,左闭右开
            if(otherParams.get("minAge")!=null){
                predicates.add(criteriaBuilder.greaterThan(root.get("age"),Integer.parseInt(otherParams.get("minAge").toString())));
            }
            if(otherParams.get("maxAge")!=null){
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("age"),Integer.parseInt(otherParams.get("maxAge").toString())));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        },pageable);
    }

一切尽在代码中…

本示例集合了几种常见查询,模糊搜索,精确搜索,日期范围搜索等等,比较实用,可以参考。criteriaBuilder有很多查询匹配的方法,可以满足绝大部分查询需求,具体的可以在使用中看下里面的方法。

其实Person的所有属性都可以作为查询条件,可以利用java反射拿到所有属性,然后来个循环每个属性都可以加进去。

2018-08-24


6.JPA 关联表自定义动态查询

在实际业务中,可能要关联表查询,并且查询条件是动态的,这就需要在自定义查询的基础上再来一波。

1.新建一个分数类,跟student是多对一的关系

package com.just.springjpa.domain;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Table(name = "course_score")
public class CourseScore {
    @Id
    @GeneratedValue
    private Long id;
    private BigDecimal score;
    private Date createDate;
    private String course;
    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public BigDecimal getScore() {
        return score;
    }

    public void setScore(BigDecimal score) {
        this.score = score;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }
}

2.student中可以再加个分数列表,一对多,懒加载,(这个list也可以不加,需要用到时可以再加)

    @JsonIgnore
    @OneToMany(fetch = FetchType.LAZY)
    private List<CourseScore> courseScoreList;

3.自定义查询,我直接写在了controller里了

repository就省略了,跟PersonRepository 一个写法

 /**
     * 根据学生姓名和最低分数查询
     * @param name 学生姓名,可为空
     * @param minScore 最低分数,可为空
     * @param pageable 分页参数
     * @return 查询到的分数结果
     */
    @GetMapping("/getScore")
    public Page<CourseScore> getScore(@RequestParam(required = false) String name,
                                      @RequestParam(required = false) BigDecimal minScore,
                                      @PageableDefault(size = 20) Pageable pageable){
        //关联动态查询
        Page<CourseScore> courseScores=courseScoreRepository.findAll(new Specification<CourseScore>() {
            @Override
            public Predicate toPredicate(Root<CourseScore> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicatesList = new ArrayList<>();
                //join里面的参数写法有好几种,这里采用最简单的一种,直接写属性名,关联的Student,内联
                Join<Student,CourseScore> join=root.join("student",JoinType.INNER);
                //注意name属性是在Student里面的,而join里面比较的属性都是关联的那张表里的字段,用join来获取
                if(!StringUtils.isEmpty(name)){
//                    predicatesList.add(
//                            criteriaBuilder.equal(
//                                    join.get("name"), name
//                            )
//                    );
                    predicatesList.add(
                            criteriaBuilder.like(
                                    join.get("name"), name
                            )
                    );
                }
                //分数是CourseScore里的属性,用root获取
                if(minScore!=null){
                    predicatesList.add(
                            criteriaBuilder.greaterThanOrEqualTo(
                                    root.get("score"), minScore
                            )
                    );
                }
                return criteriaBuilder.and(predicatesList.toArray(new Predicate[0]));
            }
        },pageable);
        return courseScores;
    }

4.测试结果

 

Spring Boot第八章-Spring Data JPA(续)

后台打印的sql:

Hibernate: select coursescor0_.id as id1_0_, coursescor0_.course as course2_0_, coursescor0_.create_date as create_d3_0_, coursescor0_.score as score4_0_, coursescor0_.student_id as student_5_0_ from course_score coursescor0_ inner join t_student student1_ on coursescor0_.student_id=student1_.id where (student1_.s_name like ?) and coursescor0_.score>=60 limit ?
Hibernate: select student0_.id as id1_2_0_, student0_.s_age as s_age2_2_0_, student0_.created_time as created_3_2_0_, student0_.money as money4_2_0_, student0_.s_name as s_name5_2_0_ from t_student student0_ where student0_.id=?

由此看出是inner join,并且join表的顺序也是对的,参数也是对的。当然这只是测试,不合理的地方请见谅。

2018-09-11

Spring Boot第八章-Spring Data JPA(续)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100283.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号