Boot JPA自定义查询操作
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue 发布时间:2019/8/30 17:10:37
上一节中,我们介绍了基本的数据库操作,本章节,我们将介绍更加复杂的查询和更新删除等操作。本章节分为2部分,第一部分使用使用JPA自带的查询、更新、删除等功能,可以使用特定的语法实现自定义查询,第二部分我们介绍如何使用完全自定义的SQL语句。
一、JPA的自定义操作
JPA提供了一套以接口命名方法作为其查询方式的规范,只要在我们继承了Repository接口的接口中使用JPA规范的方法命名,JPA就可以反解出对应的sql语句。
规范如下:
关键词 | 例 子 |
---|---|
IsNotNull | findByAgeNotNull |
Like | findByNameLike |
NotLike | findByNameNotLike |
StartingWith | findByNameStartingWith |
EndingWith | findByNameEndingWith |
Containing | findByNameContaining |
OrderBy | findByAgeOrderByName |
Not | findByNameNot |
In | findByAgeIn |
NotIn | findByAgeNotIn |
True | findByActiveTrue |
Flase | findByActiveFalse |
And | findByNameAndAge |
Or | findByNameOrAge |
Between | findByAgeBetween |
LessThan | findByAgeLessThan |
GreaterThan | findByAgeGreaterThan |
IsNull | findByAgeIsNull |
那么,问题就好办了。我们只要按照这个格式,结合实体类的成员变量的名字,申明相应的方法名,就可以直接使用,而无需去写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_mobilephone=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