SpringBoot系列:SpringDataJpa常用的注解标签和自定义查询语句(JPQL)

735 阅读6分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战


前言

方向不对努力白费

平常你也付出了很多的时间,但就是没有得到多少收益。就像有时候很多小伙伴问我,我是该怎么学一个我没接触过的内容。我的个人经验非常建议,先不要学太多理论性的内容,而是尝试实际操作下,把要学的内容做一些Demo案例出来。这有点像你买了个自行车是先拆了学学怎么个原理,还是先骑几圈呢?哪怕摔了跟头,但那都是必须经历后留下的经验。

前面讲了SpringDataJpa持久层操作,请查看博主的SpringDataJpa系列文章。欢迎关注!


创建实体

在com.cyj.springboot.entity下创建Student类,如下:

package com.cyj.springboot.entity; 
import java.util.Date; 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.Table; 
import org.springframework.format.annotation.DateTimeFormat; 
/*** 由于数据库没有数据表@Entity创建实体 
* @table(name="studenttb")在springbootjpahelloworlddb里面自动创建表名为studenttb的数据表 */ 
@Entity 
@Table(name="studenttb") 
public class Student { 
    @Id 
    //实体类的主键 
    @GeneratedValue 
    //自动增长列 
    private Integer studentId;
    //学生编号 
    private String studentName;
    //学生姓名 
    private Integer studentAge;
    //学生年龄 
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") 
    private Date studentBirthday;
    //学生出生年月 
    public Integer getStudentId() { 
        return studentId; 
    }
    public void setStudentId(Integer studentId) {
        this.studentId = studentId; 
    }
    public String getStudentName() { 
        return studentName; 
    }
    public void setStudentName(String studentName) {
        this.studentName = studentName; 
    }
    public Integer getStudentAge() { 
        return studentAge; 
    }
    public void setStudentAge(Integer studentAge) {
        this.studentAge = studentAge; 
    }
    public Date getStudentBirthday() { 
        return studentBirthday;
    }
    public void setStudentBirthday(Date studentBirthday) { 
        this.studentBirthday = studentBirthday; 
    }
    @Override 
    public String toString() { 
        return "Student [studentId=" + studentId + ", studentName=" + studentName + ", studentAge=" + studentAge + ", studentBirthday=" + studentBirthday + "]"; 
    } 
}

下面总结一下JPA中常用的注解标签

  • @Entity:@Entity标记在类名上面,作为实体类的标识。
  • @Table:当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列 使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。 @Table 标注的常用选项是 name,用于指明数据库的表名。 @Table标注还有一个两个选项 catalog 和 schema 用于设置表所属的数据 库目录或模式,通常为数据库名。uniqueConstraints选项用于设置约束条件,通常不须设置。
  • @Id:@Id设置对象表示符,标识的实体类的属性映射对应表中的主键。
  • @GeneratedValue:设置标识符的生成策略,常与@Id一起使用。参数:strategy指定具体的生成策略
    • 方式一:@GeneratedValue(strategy=GenerationType.AUTO) 也是默认策略, 即写成@GeneratedValue也可;类似于hibernate的native策略,生成方式取决于底层的数据库。
    • 方式二:@GeneratedValue(strategy = GenerationType.IDENTITY)指定“自动增长”策略,适用于MySQL;
    • 方式三:@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = “seq_tbl_person”)指 定“序列”策略,常用于Oracle,其中generator表示生成器的名字。而且还要指定@SequenceGenerator(name = “seq_tbl_person”, sequenceName = “seq_tbl_person”, allocationSize = 1)注解配合使用。其中name指定生成器的名字(与generator的值一样),sequenceName指定数据 库中定义序列的名字,allocationSize指定序列每次增长1。
  • @Column:描述数据库表中该字段的定义,具有一下属性。
    • name:表示数据库表中该字段的名称,默认情形属性名称一致。
    • nullable:表示该字段是否允许为null,默认为true。
    • unique:表示该字段是否是唯一标识,默认为false。
    • length:表示该字段的大小,仅对String类型的字段有效。
    • insertable:表示在ORM框架执行插入操作时,该字段是否应出现- INSETRT语句中,默认为true。
    • updateable:表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true。 对于一经创建就不可以更改的字段,该属性非常有用,如对于birthday字段。
    • columnDefinition:表示该字段在数据库中的实际类型。通常ORM框架可以根据属性类型自动判断数据 库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE,TIME还是 TIMESTAMP。此外,String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的 BLOB或TEXT字段类型,该属性非常有用。
  • @OrderBy:在加载数据的时候可以为其指定顺序。
  • @Transient:表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性。 如果一个属性并非数据库表的字段映射。就务必将其标示为@Transient。否则。ORM框架默认其注解为@Basic

自定义查询语句(JPQL)

这种查询可以声明在Repository方法中,摆脱像命名查询那样的约束,将查询直接在相应的接口方法中声明,结构更清晰,这是SpringDataJpa的特有实现

使用@Query自定义查询

  • 前面介绍的获取数据的方式都没有使用到任何的HQL(Hibernate Query Language)语句,那些方法已经可以满足 很多需求,也有时候会觉得方法名太长不太方便,下面介绍一下使用Hql方式获取数据。

例如根据具体名字查询学生信息,在StudentRepository类中添加如下方法:

@Query("select s from Student s where s.studentName = ?1") 
Student findByStudentName(String studentName);

在Controller调用,如下

/*** 
* http://localhost:8090/findStudentsByName?name=刘三 
* @param name 
* @return */ 
@RequestMapping("/findStudentsByName") 
public Object findStudentBystudentName(String name) {
    Student student = repository.findByStudentName(name);
    return student; 
}

@Query与 @Modifying的联合使用

这两个annotation一起声明,可定义个性化更新操作,例如只涉及某些字段更新时最为常用,示例如下:

  • a.如果要修改学生姓名,首先在StudentRepository下添加如下代码:
@Transactional 
@Modifying 
@Query("update Student s set s.studentName=?1 where s.studentId=?2") 
int setFixedStudentNameFor(String studentName,int studentId);
  • b.在StudentController里面进行调用,代码如下:
/*** 
* http://localhost:8090/setStudent?name=lucy&id=2 
* @param name 
* @return */ 
@RequestMapping("/setStudent") 
public Object setStudentByName(String name,int id) { 
    int i = repository.setFixedStudentNameFor(name,id); 
    Map<String,Object> map=new HashMap<String,Object>(); 
    if(i>0) { 
        map.put("success", true); 
    }else {
        map.put("success", false); }return map; 
    }
}

索引参数与命名参数

  1. 索引参数如下例代码所示,索引值从1开始,查询中 ”?X” 个数需要与方法定义的参数个数相一致,并且顺序也 要一致
@Transactional 
@Modifying 
@Query("update Student s set s.studentName=?1 where s.studentId=?2") 
int setFixedStudentNameFor(String studentName,int studentId);
  1. 命名参数(推荐使用这种方式) 可以定义好参数名,赋值时采用@Param("参数名"),而不用管顺序。如下所 示:
    • a.在StudentRepository里添加如下代码:
@Query("select s from Student s where s.studentName like %:studentName% ") 
List<Student> queryByname(@Param(value = "studentName") String studentName);
- b.在StudentController里面进行调用,代码如下:
/*** 
* http://localhost:8090/queryByname?name=刘 
* @param name 
* @return */ 
@RequestMapping("/queryByname") 
public Object queryByname(String name) { 
    List<Student> student = repository.queryByname(name); 
    return student; 
}

好了到这里也该结束了,下一篇讲解--SpringDataJpa的原生Sql查询,各位要自己多动手才能学到真正的东西。加油各位


最后

  • 更多参考精彩博文请看这里:《陈永佳的博客》

  • 喜欢博主的小伙伴可以加个关注、点个赞哦,持续更新嘿嘿!