课程表

Spring Boot课程

工具箱
速查手册

Boot JPA自定义查询操作

当前位置:免费教程 » Java相关 » Spring Boot
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2019/8/30 17:10:37

上一节中,我们介绍了基本的数据库操作,本章节,我们将介绍更加复杂的查询和更新删除等操作。本章节分为2部分,第一部分使用使用JPA自带的查询、更新、删除等功能,可以使用特定的语法实现自定义查询,第二部分我们介绍如何使用完全自定义的SQL语句。

一、JPA的自定义操作

JPA提供了一套以接口命名方法作为其查询方式的规范,只要在我们继承了Repository接口的接口中使用JPA规范的方法命名,JPA就可以反解出对应的sql语句。

规范如下:

关键词例 子
IsNotNullfindByAgeNotNull
LikefindByNameLike
NotLikefindByNameNotLike
StartingWithfindByNameStartingWith
EndingWithfindByNameEndingWith
ContainingfindByNameContaining
OrderByfindByAgeOrderByName
NotfindByNameNot
InfindByAgeIn
NotInfindByAgeNotIn
TruefindByActiveTrue
FlasefindByActiveFalse
AndfindByNameAndAge
OrfindByNameOrAge
BetweenfindByAgeBetween
LessThanfindByAgeLessThan
GreaterThanfindByAgeGreaterThan
IsNullfindByAgeIsNull

 那么,问题就好办了。我们只要按照这个格式,结合实体类的成员变量的名字,申明相应的方法名,就可以直接使用,而无需去写SQL语句。

但是这里有个问题需要注意,JPA只支持名称首字母小写的成员变量,如果名称变量是大写的,比如我把MainBean实体类里面的name成员变量改为"Name",则会出现类似如下的错误:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainRestController': Unsatisfied dependency expressed through field 'mainServiceImpl'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainServiceImpl': Unsatisfied dependency expressed through field 'mainDao'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainDao': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.w3xue.jiaocheng.MainDao.findByNameLike(java.lang.String)! Unable to locate Attribute  with the the given name [name] on this ManagedType [com.w3xue.jiaocheng.MainBean]
......

一切准备就绪后,我们首先在MainDao类里申明2个根据命名规范来的函数:

List<MainBean> findByNameLike(String Name);
List<MainBean> findByAgeBetween(Integer a,Integer b);

这2个方法,一个是通过名称查找对象,一个是通过年龄的区间来查找对象,其引用也非常直接,你可以在MainRestController类里直接申明下面这个方法来引用它们:

@RequestMapping(value="/jpagetdiy/{name}",method= RequestMethod.GET)
public String jpaGetDiy(@PathVariable(value = "name",required = true) String pName) {
    try
    {
        String selectName = "%" + pName + "%";
        List<MainBean> mbStudents = mainDao.findByNameLike(selectName);
        StringBuilder sbInfo=new StringBuilder();
        for (MainBean mbSingle:mbStudents) {
            sbInfo.append("名称查找结果:【ID:"+mbSingle.getId()+"】");
            sbInfo.append(" 【姓名:"+mbSingle.getName()+"】");
            sbInfo.append(" 【年级和班级:"+mbSingle.getGrade()+" "+mbSingle.getStudentClass()+"】");
        }

        List<MainBean> mbStudents2 = mainDao.findByAgeBetween(10,15); //查找10岁至15岁之间的学生,李四符合条件
        for (MainBean mbSingle:mbStudents2) {
            sbInfo.append("<br />年龄区间查找结果:【ID:"+mbSingle.getId()+"】");
            sbInfo.append(" 【姓名:"+mbSingle.getName()+"】");
            sbInfo.append(" 【年级和班级:"+mbSingle.getGrade()+" "+mbSingle.getStudentClass()+"】");
        }

        return sbInfo.toString();
    }
    catch (Exception e)
    {
        return "未查询到数据";
    }
}

这里引用了2个方法,一个是根据名字模糊查找学生信息,另外一个是查找年龄在10岁至15岁之间的学生信息。如果一切顺利,就会返回如下信息:

名称查找结果:【ID:1】 【姓名:张三】 【年级和班级:二年级 三班】
年龄区间查找结果:【ID:2】 【姓名:李四】 【年级和班级:五年级 六班】

其他的命名格式你可以自行尝试,根据名称和你的实体类成员变量名字来定义方法名就行了。


二、完全自定义SQL语句的JPA操作

让我们来看看完全自定义SQL语句的JPA操作。

首先,我们先访问如下地址:

http://localhost:8080/jiaocheng/adminlogin?pwd=mypassword

访问这个页面后,就获得一个键为“user”的session,然后访问添加数据的这个接口地址:

http://localhost:8080/jiaocheng/jpatest?name=李四&age=11&grade=四年级&studentclass=一班&parent_name=王老五&parent_moblephone=12388998899

如果没有意外,就会返回“添加学生李四成功”的信息。否则,如果session为空,或有其他错误,则提示添加失败。

但是,此时我们发现之前已经添加过李四的信息了,这次是姓名弄错了,需要修改姓名,怎么办呢?我们使用完全自定义的JPA操作。首先我们在MainDao类中添加如下注释和方法体:

//修改名字
@Modifying
@Transactional
@Query(value="update t_w3xue_student set f_name=:name where f_id=:id",nativeQuery = true)
public void upStudentById(@Param("name") String sName,@Param("id") Integer nId);

@Modifying注释表明这是一个有修改功能的自定义方法体,@Transactional表明这是一个事务,因为涉及到修改数据库,这2个注解少一不可。第三个注解@Query里面包含自定义的SQL语句,但是这个“SQL”语句跟传统的SQL语句还是有不同的地方,你可以发现多了“:name”、“:id”这样的语句,前面带冒号表明,这2个参数是从底下的方法体引用的,实际上,它一般被称为HQL。“nativeQuery = true”表明,里面对应的是原始的表名,如果设置nativeQuery = false”则对应的实体名。比如,我们设置这个方法体如下,效果是一模一样的

//修改名字
@Modifying
@Transactional
@Query(value="update MainBean set f_name=:name where f_id=:id",nativeQuery = false)
public void upStudentById(@Param("name") String sName,@Param("id") Integer nId);

方法申明中,@Param注解里的值,必须和上面一行HQL里面的冒号后面的变量名一致,但是在接受外来参数的时候,可以不必设置为和HQL里面的冒号后面的变量名一样,例如,本例中我们就把接受的2个参数分别申明为sName和nId。

我们在MainRestController类中添加如下方法:

@RequestMapping(value="/jpadiymodicomplete",method= RequestMethod.GET)
public String jpaDiyModiComplete(@RequestParam(value = "id",defaultValue = "") Integer pId,@RequestParam(value = "name",defaultValue = "") String pName, HttpSession session)
{
    try
    {
        if (session.getAttribute("admin").toString().length()>0) {
            mainDao.upStudentById(pName,pId); //将ID为“参数id”的数据,姓名修改为“参数name”的值
            return "操作成功";
        }
        else
        {
            return "操作失败,没有权限";
        }
    }
    catch (Exception e)
    {
        return "操作失败,无权限";
    }
}

首先,我们先访问如下地址:

http://localhost:8080/jiaocheng/adminlogin?pwd=mypassword

访问这个页面后,就获得一个键为“user”的session,然后访问添加数据的这个接口地址:

http://localhost:8080/jiaocheng/jpadiymodicomplete?name=%E7%8E%8B%E9%BA%BB%E5%AD%90&id=3

如果之前登陆了,就会返回操作成功的提示。这时我们再查看数据库,就会发现,我们刚刚添加的ID为3的学生记录,名字已经被修改为“王麻子”了。

我们不但可以使用这个完全自定义的方法update数据,而且也可以用来delete、insert操作,因为方法一模一样,此处不再赘述。

但自定义查询的办法有所不同,这里简要介绍一下。首先我们在MainDao类中添加如下注释和方法体:

@Query(value = "SELECT * FROM t_w3xue_student where f_name like %:name%", nativeQuery = true)
public List<MainBean> getStudentByName(@Param("name") String sName);

然后,在MainRestController类中添加如下方法:

@RequestMapping(value="/jpadiygetcomplete",method= RequestMethod.GET)
public String jpaDiyGetComplete(@RequestParam(value = "name",defaultValue = "") String pName, HttpSession session)
{
    try {
        StringBuilder sbInfo = new StringBuilder();
        List<MainBean> mbStudents = mainDao.getStudentByName(pName);
        sbInfo.append("完全模糊查找结果:");
        for (MainBean mbSingle : mbStudents) {
            sbInfo.append("<br />【ID:" + mbSingle.getId() + "】");
            sbInfo.append(" 【姓名:" + mbSingle.getName() + "】");
            sbInfo.append(" 【年级和班级:" + mbSingle.getGrade() + " " + mbSingle.getStudentClass() + "】");
        }
        return sbInfo.toString();
    }
    catch (Exception e)
    {
        return "查询失败";
    }
}

然后,我们访问如下地址:

http://localhost:8080/jiaocheng/jpadiygetcomplete?name=%E7%8E%8B

模糊查询一个“王”字,我们就会GET到如下的结果:

完全模糊查找结果:
【ID:3】 【姓名:王麻子】 【年级和班级:四年级 一班】

现在,完全自定义的操作,包括update、insert、delete、select都已经实现了。

注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2019/8/30 17:10:37