Spring Boot Jpa之构建动态SQL查询语句

Spring Boot Jpa之构建动态SQL查询语句

概念 

创建使用Java Persistence API的存储库是一个繁琐的过程,需要大量时间并需要大量样板代码。一种推荐的方式是使用

1.JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。,而Hibernate是它的一种实现。除了Hibernate,还有EclipseLink(曾经的toplink),OpenJPA等可供选择,所以使用Jpa的一个好处是,可以更换实现而不必改动太多代码。

2.Hibernate作为JPA的一种实现,jpa的注解已经是hibernate的核心,hibernate只提供了一些补充,而不是两套注解。hibernate对jpa的支持够足量,在使用hibernate注解建议使用jpa。

使用criteria 查询简单Demo

1.实体类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;
import java.util.Date;

/**
 * 学生 实体类
 * @jason.zhong
 */
@Entity
@DynamicUpdate(true)
@DynamicInsert(true)
@Table(name="student")
@JsonIgnoreProperties(value={"hibernateLazyInitializer", "handler"})
public class StudentVo {

    /**
     * 主键
     */
    @Id
    @GenericGenerator(name = "uuidGenerator", strategy = "org.hibernate.id.UUIDGenerator") // 唯一性不受进程重启,机器重启等影响UUID生成方式
    @GeneratedValue(generator = "uuidGenerator") // 使用上面定义的uuidGenerator作为主键生成器
    @Column(name = "id", columnDefinition="CHAR(36)", unique = true, nullable = false, insertable = false, updatable = false)
    private String id;

    /**
     * 创建时间
     */
    @Column(name = "created_at", columnDefinition="DATETIME", nullable = false, updatable = false)
    @JSONField(format="yyyy-MM-dd HH:mm:ss")
    private Date createdAt;

    /**
     * 修改时间
     */
    @Column(name = "updated_at", columnDefinition="DATETIME")
    @JSONField(format="yyyy-MM-dd HH:mm:ss")
    private Date updatedAt;

    /**
     * 学号
     */
    @Column(name = "student_no", columnDefinition="INTEGER(10) UNSIGNED")
    private Integer studentNo;

    /**
     * 姓名
     */
    @Column(name="name", columnDefinition="VARCHAR(50)")
    private String name;

    /**
     * 性别
     */
    @Column(name="sex", columnDefinition="TINYINT(1) UNSIGNED")
    private Short sex;

    /**
     * 年龄
     */
    @Column(name = "age", columnDefinition="INTEGER(3) UNSIGNED")
    private Integer age;

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }

    public String getId() {
        return id;
    }

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

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public Date getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(Date updatedAt) {
        this.updatedAt = updatedAt;
    }

    public Integer getStudentNo() {
        return studentNo;
    }

    public void setStudentNo(Integer studentNo) {
        this.studentNo = studentNo;
    }

    public String getName() {
        return name;
    }

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

    public Short getSex() {
        return sex;
    }

    public void setSex(Short sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
2.服务
import java.util.List;

/**
 * 学生 服务
 * @jason.zhong
 */
public interface StudentService {

    /**
     * 获取学生信息
     * @param student
     * @return
     */
    List<StudentVo> getAllStudent(StudentVo student);
}
3.实现类
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

/**
 * 学生 实现类
 * @jason.zhong
 */
@Service
public class StudentServiceImpl implements StudentService {

    /**
     * entityManager
     */
    @Autowired
    private EntityManager entityManager;

    /**
     * 安全查询创建工厂
     */
    private CriteriaBuilder cb = null;

    /**
     * 安全查询主语句
     */
    private CriteriaQuery<StudentVo> criteriaQuery = null;

    /**
     * Root 定义查询的From子句中能出现的类型
     */
    private Root<StudentVo> register = null;

    public StudentServiceImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
        this.cb = this.entityManager.getCriteriaBuilder();
        this.criteriaQuery = this.cb.createQuery(StudentVo.class);
        this.register = this.criteriaQuery.from(StudentVo.class);
    }

    @Override
    public List<StudentVo> getAllStudent(StudentVo student) {
        this.criteriaQuery.where(this.getPredicates(student));

        TypedQuery<StudentVo> typedQuery = this.entityManager.createQuery(this.criteriaQuery);

        List<StudentVo> result = typedQuery.getResultList();

        return result;
    }

    /**
     * 设置过滤条件
     * @param student
     * @return
     */
    private Predicate[] getPredicates(StudentVo student) {
        List<Predicate> predicate=new ArrayList<Predicate>();

        //学号
        if (student.getStudentNo() != null) {
            predicate.add(this.cb.equal(this.register.<Integer> get("studentNo"), student.getStudentNo()));
        }

        //姓名
        if (StringUtils.isNotBlank(student.getName())) {
            predicate.add(this.cb.like(this.register.<String> get("name"), '%' + student.getName()+ '%'));
        }

        //性别
        if (student.getSex() != null) {
            predicate.add(this.cb.equal(this.register.<Integer> get("sex"), student.getSex()));
        }

        //年龄
        if (student.getAge() != null) {
            predicate.add(this.cb.le(this.register.<Integer> get("age"), student.getAge()));
        }

        return predicate.toArray(new Predicate[0]);
    }
}

构建CriteriaQuery 实例API说明

1.CriteriaBuilder 安全查询创建工厂,创建CriteriaQuery,创建查询具体具体条件Predicate 等.

CriteriaBuilder是一个工厂对象,安全查询的开始.用于构建JPA安全查询.可以从EntityManager 或 EntityManagerFactory类中获得CriteriaBuilder. 

例如:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
2.CriteriaQuery 安全查询主语句

CriteriaQuery对象必须在实体类型或嵌入式类型上的Criteria 查询上起作用。 
它通过调用 CriteriaBuilder, createQuery 或CriteriaBuilder.createTupleQuery 获得。 
CriteriaBuilder就像CriteriaQuery 的工厂一样。 
CriteriaBuilder工厂类是调用EntityManager.getCriteriaBuilder 或 EntityManagerFactory.getCriteriaBuilder而得。 
StudentVo实体的 CriteriaQuery 对象以下面的方式创建:

例如:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<StudentVo> criteriaQuery = cb.createQuery(StudentVo.class);
3.Root 定义查询的From子句中能出现的类型

AbstractQuery是CriteriaQuery 接口的父类。它提供得到查询根的方法。 
Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似。 
Root实例也是类型化的,且定义了查询的FROM子句中能够出现的类型。 
查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。 
Criteria查询,可以有多个查询根。 
StudentVo实体的查询根对象可以用以下的语法获得 :

例如:

Root<StudentVo> register = criteriaQuery.from(StudentVo.class);

4.Predicate 过滤条件

过滤条件应用到SQL语句的FROM子句中。 
在criteria 查询中,查询条件通过Predicate 或Expression 实例应用到CriteriaQuery 对象上。 
这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上。 
CriteriaBuilder 也是作为Predicate 实例的工厂,Predicate 对象通过调用CriteriaBuilder 的条件方法( equal,notEqual, gt, ge,lt, le,between,like等)创建。 
Predicate 实例也可以用Expression 实例的 isNull, isNotNull 和 in方法获得,复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建。 
下面的代码片段展示了Predicate 实例查询学号为10010303的学生实例:

例如:

Predicate predicate = cb.equal(register.<Integer> get("studentNo"), 10010303);
criteriaQuery.where(predicate);
5.排序结果

Criteria查询的结果能调用CriteriaQuery.orderBy方法排序,该方法接收一个Order对象做为参数。通过调用 CriteriaBuilder.asc 或 CriteriaBuilder.Desc,Order对象能被创建。以下代码片段中,StudentVo实例是基于name的升序排列。

criteriaQuery.orderBy(cb.asc(register.<String> get("name")));
6.分页
Criteria查询的结果能调用typedQuery.setFirstResult(int).setMaxResults(int)方法来进行分页,setFirstResult设置开始位置(下标从0开始),setMaxResults设置每页显示条数
TypedQuery<StudentVo> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.setFirstResult(0).setMaxResults(10);
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值