Mybatis 快速入门之 动态sql和分页

目录

一:动态sql的基本概念

二:基本的动态sql标签

if标签

trim标签

choose标签

set标签

where标签

二:参数传递

1.单个参数:------------>八大基础类型与String类型

注意:

1.传递String的参数,必须使用@Param方式,并且指明参数名

2.在service接口,方法应该要将@param()去除掉,只留下变量名,在mapper层可以留下@param(),以防万一,防止报错

2.多个参数

3.实体参数

三:模糊查询

1.${}

2.#{}

3.concat()---->mysql函数

问题:#{...}与${...}区别? 

   注:          (1)mybatis中使用OGNL表达式传递参数          (2) 优先使用#{...}          (3) ${...}方式存在SQL注入风险

问:SQL注入风险

四:查询返回结果集

案例①:使用resultMap返回自定义类型集合

案例②: 使用resultType返回单个对象

案例③:使用resultType返回Map,适用于多表查询返回结果集,object>

案例④: 使用resultType返回List

五:分页查询

  为什么要重写mybatis的分页?          Mybatis的分页功能很弱,它是基于内存的分页(查出所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没有用的

1.导入分页插件

2. 将pagehelper插件配置到mybatis中

3.导入pageBean文件在util包下

4.在BookMapper类定义方法

5.在BookMapper.xml文件中进行sql语句的编写

6.在iBookService类编写代码

7.实现接口所定义的方法

8.在你需要进行分页的Mybatis方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个Mybatis查询方法会被进行分页

9. 获取分页信息(二种方式)

六:特殊字符处理

案例:价格范围查询

七:批量新增

重点:

        allowMultiQueries=true 允许一条SQL语句包含多个执行SQL以分号;分隔,是必须添加的


一:动态sql的基本概念

            动态sql是指在进行sql操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况;

二:基本的动态sql标签

  • if标签

①:在BookMapper类定义包含if标签方法

//if标签
    List queryBookByIf(Book book);

②:在BookMapper.xml文件中进行sql语句的编写

  当满足test条件时,才会将if标签内的sql语句拼接上去

③:在iBookService类编写代码

    //mybatis之if标签
    List queryBookByIf(Book book);

④:进行 junit4单元测试

------测试带type类型的查询:

 @Test
    //mybatis之if标签
    public  void  queryBookByIf(){
        List bookList = iBookService.queryBookByIf(Book.builder().btype("历史").build());
        bookList.forEach(System.out::println);
    }

测试结果如下:   Mybatis 快速入门之 动态sql和分页_第1张图片

查看sql语句:

 ---测试不type类型的查询:

 @Test
    //mybatis之if标签
    public  void  queryBookByIf(){
        List bookList = iBookService.queryBookByIf(Book.builder().build());
        bookList.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第2张图片

 查看sql语句:

  • trim标签

    trim标签属性:

   prefix 前缀
   suffix 后缀
  suffixOverride 去除后缀指定的字符
 prefixOverrides 去除前缀指定的字符

①:在BookMapper类定义包含trim标签方法

 int insertSelective(Book record);

②:在BookMapper.xml文件中进行sql语句的编写


    insert into t_book
    
      
        bid,
      
      
        bname,
      
      
        bprice,
      
      
        btype,
      
    
    
      
        #{bid,jdbcType=INTEGER},
      
      
        #{bname,jdbcType=VARCHAR},
      
      
        #{bprice,jdbcType=INTEGER},
      
      
        #{btype,jdbcType=VARCHAR},
      
    
  

  • foreach标签

foreach标签属性:

collection 被遍历的集合或数组
item 每次循环遍历的集合名
separator 每次循环的分隔符
index 下标
open 开始位置
close 关闭位置

①:编写一个类,储存需要遍历的集合或者数组

package com.zking.vo;

import com.zking.model.Book;
import lombok.Data;

import java.util.List;

/**
 * @author 唐渊
 * @create  2022-07-23 9:26
 */
@Data //getter/setter/toString
public class BookVo extends Book {
    //foreach标签需要遍历的list集合
    private List ids;


}

②:在BookMapper类定义包含foreach标签方法

 //foreach标签
    List queryBookByForeach(BookVo bookVo);

③:在BookMapper.xml文件中进行sql语句的编写

    (1)方式一:

(2)方式二:

 select
    
    from t_book where 1=1
    
      #{id}
    

(3)方式三:

 select
    
    from t_book where 1=1 and bid in
    (
    
      #{id}
    

④:在iBookService类编写代码

 //foreach标签
    List queryBookByForeach(BookVo bookVo);

⑤:进行 junit4单元测试

  @Test
   //foreach标签
    public void  queryBookByForeach(){
       BookVo bookVo=new BookVo();
       //Arrays.asList--->将数组转换为集合
       bookVo.setIds(Arrays.asList(new Integer[]{13,17,3}));
       List books = iBookService.queryBookByForeach(bookVo);
       books.forEach(System.out::println);
   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第3张图片

查看sql语句: 

  • choose标签

               choose 标签作用是通过条件判断来拼接 SQL 语句,类似于 Java 中的 switch 语句,从上到下,当有匹配的条件时,跳出 choose 语句;如果所有条件都不成立则执行 otherwise 标签中的内容,使用 choose 标签的时候,一定要注意最先需要判断的条件要放在前面,当匹配到某个条件时,就不会判断后面的语句了

语法格式:


	
		...
	
	
		...
	
	
		...
	
	...
	
		...
	

①:在BookMapper类定义包含choose标签方法

//choose 标签
     List queryBookByChoose(Book book);

②:在BookMapper.xml文件中进行sql语句的编写

③:在iBookService类编写代码

    List queryBookByChoose(Book book);

④:实现接口所定义的方法

@Override
    public List queryBookByChoose(Book book) {
        return bookMapper.queryBookByChoose(book);
    }

⑤:进行 junit4单元测试

------测试带name类型的查询:

 @Test
   //choose 标签
    public void  queryBookByChoose(){
       List books = iBookService.queryBookByChoose(Book.builder().bname("之").build());
       books.forEach(System.out::println);

   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第4张图片

 

查看sql语句: 

 

------测试带type类型的查询:

  @Test
   //choose 标签
    public void  queryBookByChoose(){
       List books = iBookService.queryBookByChoose(Book.builder().btype("历史").build());
       books.forEach(System.out::println);

   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第5张图片

查看sql语句: 

 

------测试带id类型的查询:

 @Test
   //choose 标签
    public void  queryBookByChoose(){
List books = iBookService.queryBookByChoose(Book.builder().bid(30).build());
       books.forEach(System.out::println);

   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第6张图片

 

查看sql语句: 

 

  • set标签

            set用于更新的sql语句中,在update时,多条件更新,每个属性后面要加逗号“,”,这个时候可能会出现多一个“,”的情况,此时我们就可以使用set去掉后边的“,”修改方法,假如实体类属性为空就不修改此属性所对于的字段

①:在BookMapper类定义包含set标签方法

 //set标签
    int updateByPrimaryKeySelective(Book record);

②:在BookMapper.xml文件中进行sql语句的编写

 
    update t_book
    
      
        bname = #{bname,jdbcType=VARCHAR},
      
      
        bprice = #{bprice,jdbcType=INTEGER},
      
      
        btype = #{btype,jdbcType=VARCHAR},
      
    
    where bid = #{bid,jdbcType=INTEGER}
  

③:在iBookService类编写代码

 int updateByPrimaryKeySelective(Book record);

④:实现接口所定义的方法

 @Override
    public int updateByPrimaryKeySelective(Book record) {
        return bookMapper.updateByPrimaryKeySelective(record
        );
    }

⑤:进行 junit4单元测试

 public void updateByPrimaryKeySelective(){
       book.setBid(27);
       book.setBname("剑与荣光");
       book.setBprice(45);
       book.setBtype("文学");
       iBookService.updateByPrimaryKeySelective(book);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第7张图片

 

查看sql语句: 

Mybatis 快速入门之 动态sql和分页_第8张图片

 

  • where标签

    where标签只会在至少有一个子元素返回了SQL语句时, 才会向SQL语句中添加WHERE,并且如果WHERE之后是以AND或OR开头,会自动将其删掉。

①:在BookMapper类定义包含where标签方法

 //where标签
    List  queryBookWhere(Book book);

②:在BookMapper.xml文件中进行sql语句的编写

 

③:在iBookService类编写代码

 //where标签
    List  queryBookWhere(Book book);

④:实现接口所定义的方法

  @Override
    public List queryBookWhere(Book book) {
        return bookMapper.queryBookWhere(book);
    }

⑤:进行 junit4单元测试

------测试带name类型的查询:

  @Test
    //where标签
    public void queryBookWhere(){
        List books = iBookService.queryBookWhere(Book.builder().bname("的").build());
        books.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第9张图片

 

查看sql语句:

Mybatis 快速入门之 动态sql和分页_第10张图片

 

------测试带type类型的查询:

 @Test
    //where标签
    public void queryBookWhere(){
      List books = iBookService.queryBookWhere(Book.builder().btype("文学").build());
        books.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第11张图片

 

查看sql语句:

Mybatis 快速入门之 动态sql和分页_第12张图片

 

二:参数传递

1.单个参数:------------>八大基础类型与String类型

   ①:案例演示:Integer参数传递

(1):在BookMapper类定义方法

 List queryBookByInteger(Integer bid);

(2):在BookMapper.xml文件中进行sql语句的编写

(3):在iBookService类编写代码

  List queryBookByInteger(Integer bid);

(4):实现接口所定义的方法

 @Override
    public List queryBookByInteger(Integer bid) {
        return bookMapper.queryBookByInteger(bid);
    }

(5):进行 junit4单元测试

---------不传递参数的测试演示(相当于查询所有)

 @Test
    public void queryBookByInteger(){
       List books = iBookService.queryBookByInteger(null);
        books.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第13张图片

 

查看sql语句:

     ok,不带id参数的测试,通过sql语句可以看出来,相当于查询所有,那么我们再来进行带id参数的测试:

  @Test
    public void queryBookByInteger(){
        List books = iBookService.queryBookByInteger(3);
        books.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第14张图片

           很好,出现了bug,没有bug的程序猿,都是没有完整的程序猿人生的,我们一起来分析为什么会出现bug:

 报错提示:

 org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'bid' in 'class java.lang.Integer'
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'bid' in 'class java.lang.Integer'

分析:当前的bid没有getter方法,反射异常-----传递的是一个属性,不是一个实体类,如何给它getter方法?

  
      and bid=#{bid}
    

   所以,错误点在BookMapper.xml文件中的bid,如果传递的是八大基本类型,就必须使用value,value就代表当前的值

    所以,将BookMapper.xml文件中的变为:

  
      and bid=#{bid}
    

     继续测试,看效果,查看是否可以运行:

Mybatis 快速入门之 动态sql和分页_第15张图片

 查看sql语句:

 OK,nice,将xml文件在的bid全部转换为value(注意:数据库的字段除外),来继续尝试:


      and bid=#{value}
    

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第16张图片

  查看sql语句:

Mybatis 快速入门之 动态sql和分页_第17张图片

      ok,nice~~~~nice,继续往下走~~~~··

     ps:

  • 传递Integer类型的参数,相当于传递八大基础类型

   ②:案例演示:String参数传递

(1):在BookMapper类定义方法

 //传递String类型的参数
 List queryBookByString(String btype);

(2):在BookMapper.xml文件中进行sql语句的编写

  

(3):在iBookService类编写代码

  //传递String类型的参数
    List queryBookByString(String btype);

(4):实现接口所定义的方法

 @Override
    public List queryBookByString(String btype) {
        return bookMapper.queryBookByString(btype);
    }

(5):进行 junit4单元测试

 @Test
    //传递String类型的参数
    public void queryBookByString(){
        List books = iBookService.queryBookByString("历史");
        books.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第18张图片

 报错提示:

 org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: invalid comparison: java.lang.String and [C
### Cause: java.lang.IllegalArgumentException: invalid comparison: java.lang.String and [C

很好,又出现了bug,继续分析:

       这个异常是属于参数异常的类型,不知道是什么哪里有问题,那么我们不妨大胆猜测一下,有可能是xml文件中不能使用value,改用btype尝试尝试


   and btype=#{btype}

 好,继续运行,看看结果:

    Mybatis 快速入门之 动态sql和分页_第19张图片

 报错提示:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'btype' in 'class java.lang.String'
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'btype' in 'class java.lang.String'
 

分析:很好,出现了bug,不过这个bug是和上面出现的bug一样,说明还是要使用value,那么我们就将所有的btype统统改为value,继续运行运行尝试尝试~~~

 
      and btype=#{value}
    

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第20张图片

 OK,还是在报我们第一次运行时的错误,一直在报错,这就告诉我们String类型的传参不能这么直接传参,还需要额外的参数,那么我们将BookMapper类的方法用注解的方法进行额外的设参,用@param()的方式进行设参,例如我的String类型的传递参数问题解决方案如下:

    //bookType-->参数
    //btype-->变量名
   List queryBookByString(@Param("bookType") String btype);

   mapper的映射文件如老样子,不进行修改,进行运行,看是否会报错

 
      and btype=#{value}
    

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第21张图片

 报错提示:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'value' not found. Available parameters are [param1, bookType]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'value' not found. Available parameters are [param1, bookType]
 

好,天意难违,bug还是出现了,我们继续来分析:这里的报错显示value没有被分析,那么我们不妨可以得出是xml映射文件的sql语句中,不能使用value,要使用我们在mapper层中定义方法所用@param()方式设置的参数,来继续进行测试一波

 
      and btype=#{bookType}
    

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第22张图片

      好,传递String类型的参数的bug终于解决掉了,当我们遇到bug时,不要放弃,要大胆尝试,从另一个方向分析出发,可能会有意外的收获

注意:

1.传递String的参数,必须使用@Param方式,并且指明参数名

2.在service接口,方法应该要将@param()去除掉,只留下变量名,在mapper层可以留下@param(),以防万一,防止报错

2.多个参数

①:在BookMapper类定义方法

 List queryBookParams(@Param("booktype") String btype,
                           @Param("bookid") Integer bid);

②:在BookMapper.xml文件中进行sql语句的编写

③:在iBookService类编写代码

  List queryBookParams(String btype, Integer bid);

注意:方法在mapper层和service接口所定义的方法格式不一样,请认真区分并遵循

④:实现接口所定义的方法

 @Override
    public List queryBookParams(String btype, Integer bid) {
        return bookMapper.queryBookParams(btype,bid);
    }

⑤:进行 junit4单元测试

public  void queryBookParams(){
         List books = iBookService.queryBookParams("文学", 27);
         books.forEach(System.out::println);
     }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第23张图片

 

查看sql语句:

 

3.实体参数

①:在BookMapper类定义方法

 List queryBookByObject(Book book);

②:在BookMapper.xml文件中进行sql语句的编写

 @Override
    public List queryBookByObject(Book book) {
        return bookMapper.queryBookByObject(book);
    }

③:在iBookService类编写代码

  List queryBookByObject(Book book);

④:实现接口所定义的方法

@Override
    public List queryBookByObject(Book book) {
        return bookMapper.queryBookByObject(book);
    }

⑤:进行 junit4单元测试

 @Test
    public void queryBookByObject(){
         List books = iBookService.queryBookByObject(Book.builder().btype("文学").build());
         books.forEach(System.out::println);
     }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第24张图片

 

查看sql语句:

 

三:模糊查询

①:在BookMapper类定义方法

 List queryBookLike(Book book);

②:在BookMapper.xml文件中进行sql语句的编写

③:在iBookService类编写代码

  //模糊查询
    List queryBookLike(Book book);

④:实现接口所定义的方法

 @Override
    public List queryBookLike(Book book) {
        return bookMapper.queryBookLike(book);
    }

1.${}

重点:相当于占位符,参数传递时需要手动拼接%%百分号 例如:"zs"-->'zs' 会自动拼接单引号
 

⑤:进行 junit4单元测试

方式一:使用${}方式进行模糊查询

  @Test
     //模糊查询
    public void queryBookLike(){
         List books = iBookService.queryBookLike(Book.builder().bname("%与%").build());
         books.forEach(System.out::println);
     }

   

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第25张图片

 

查看sql语句:

Mybatis 快速入门之 动态sql和分页_第26张图片

 

2.#{}

重点:使用$传递参数时,只会传递参数本身--->例如:"zs"-->zs 不会自动拼接单引号

⑤:进行 junit4单元测试

方式二:使用#{}方式进行模糊查询

  @Test
     //模糊查询
    public void queryBookLike(){
         List books = iBookService.queryBookLike(Book.builder().bname("与").build());
         books.forEach(System.out::println);
     }

测试结果如下:

 
      and bname like '%${bname}%'
    

Mybatis 快速入门之 动态sql和分页_第27张图片

 

查看sql语句:

3.concat()---->mysql函数

⑤:进行 junit4单元测试

方式三:使用concat()方式进行模糊查询

 
      and bname like concat('%',#{bname},'%')
    

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第28张图片

 

查看sql语句:

问题:#{...}与${...}区别? 

答:参数类型为字符串,#会在前后加单引号['],$则直接插入值

   注:
          (1)mybatis中使用OGNL表达式传递参数
          (2) 优先使用#{...}
          (3) ${...}方式存在SQL注入风险
 

问:SQL注入风险

           数据库要执行 SQL 访问数据,数据库是个执行机构,它只会检查传来的 SQL 是不是合乎语法,而并不会关心这个语句是否会造成伤害(数据泄露或破坏)。正因为只要符合语法规则就会执行的机制,导致 SQL 有了注入的风险。
            SQL 本身就是个字符串,而且一般没有加密,字符串可能被黑客劫持修改,这样就可能造成数据库执行了不该执行的动作。
            SQL 注入的惯用做法是通过把 SQL 子串插入到 Web 表单项或页面请求(Url)的查询字符串中提交,最终达到欺骗服务器执行恶意操作的目的。
常见案例包括通过植入 SQL 骗过登录验证。而之前很多影视网站泄露 VIP 会员密码的事件,很多就是通过 SQL 植入到 WEB 表单暴露的,并且这类表单特别容易受到攻击。通过 SQL 植入,不仅可以非法获取账号信息,严重的还能够篡改、删除重要数据信息。
 

四:查询返回结果集

   返回结果集的类型:

  • resultMap:适合使用返回值是自定义实体类的情况
  • resultType:适合使用返回值的数据类型是非自定义的,即jdk的提供的类型

案例①:使用resultMap返回自定义类型集合

(1):在BookMapper类定义方法

 List queryBookByResultMap();

(2):在BookMapper.xml文件中进行sql语句的编写

(3):在iBookService类编写代码

 List queryBookByResultMap();

(4):实现接口所定义的方法

 @Override
    public List queryBookLike(Book book) {
        return bookMapper.queryBookLike(book);
    }

(5):进行 junit4单元测试

  @Test
     //查询返回结果集
     //resultMap:适合使用返回值是自定义实体类的情况
     //resultType:适合使用返回值的数据类型是非自定义的,即jdk的提供的类型
    public void queryBookByResultMap(){
        List books = iBookService.queryBookByResultMap();
         books.forEach(System.out::println);
     }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第29张图片

 

查看sql语句:

 

案例②: 使用resultType返回单个对象

(1):在BookMapper类定义方法

Book querySingleBookById(Integer bid);

(2):在BookMapper.xml文件中进行sql语句的编写

(3):在iBookService类编写代码

 Book querySingleBookById(Integer bid);

(4):实现接口所定义的方法

 @Override
    public Book querySingleBookById(Integer bid) {
        return bookMapper.querySingleBookById(bid);
    }

(5):进行 junit4单元测试

 @Test
   //使用resultType返回单个对象
    public  void  querySingleBookById(){
       Book book = iBookService.querySingleBookById(13);
       System.out.println(book);
   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第30张图片

查看sql语句:

案例③:使用resultType返回Map,适用于多表查询返回结果集

(1):在BookMapper类定义方法

 Map querySingleBookByMap(Integer bid);

(2):在BookMapper.xml文件中进行sql语句的编写

 

(3):在iBookService类编写代码

Map querySingleBookByMap(Integer bid);

(4):实现接口所定义的方法

@Override
    public Map querySingleBookByMap(Integer bid) {
        return bookMapper.querySingleBookByMap(bid);
    }

(5):进行 junit4单元测试

 @Test
     public  void querySingleBookByMap(){
         Map book1 = iBookService.querySingleBookByMap(13);
         System.out.println(book1);
     }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第31张图片

 

查看sql语句:

案例④: 使用resultType返回List

(1):在BookMapper类定义方法

  List> queryBookByMaps();

(2):在BookMapper.xml文件中进行sql语句的编写

(3):在iBookService类编写代码

List> queryBookByMaps();

(4):实现接口所定义的方法

 @Override
    public List> queryBookByMaps() {
        return bookMapper.queryBookByMaps();
    }

(5):进行 junit4单元测试

 @Test
     //List和Map集合,适用于多表联查返回综合结果集
     public  void queryBookByMaps(){
         List> maps = iBookService.queryBookByMaps();
         System.out.println(maps);

     }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第32张图片

 

查看sql语句:

 

五:分页查询

  为什么要重写mybatis的分页?
          Mybatis的分页功能很弱,它是基于内存的分页(查出所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没有用的

 

实现分页查询的步骤:

1.导入分页插件

 
         com.github.pagehelper
         pagehelper
         5.1.2
       

例如:我的pom.xml文件




  4.0.0

  com.zking
  mybatis01
  1.0-SNAPSHOT
  war

  mybatis01 Maven Webapp
  
  http://www.example.com

  
    UTF-8
    1.8
    1.8
    
    4.13
    
    4.0.1
    
   3.4.5
    
    5.1.44
    
    2.9.1
    
    1.18.24
  
  
    
    
      junit
      junit
      ${junit.version}
      test
    
    
    
      javax.servlet
      javax.servlet-api
      ${servlet.version}
      provided
    
    
    
      org.mybatis
      mybatis
      ${mybatis.version}
    
    
    
      mysql
      mysql-connector-java
      ${mysql.version}
    
    
    
    
    
      org.apache.logging.log4j
      log4j-core
      ${log4j2.version}
    
    
      org.apache.logging.log4j
      log4j-api
      ${log4j2.version}
    
    
    
      org.apache.logging.log4j
      log4j-web
      ${log4j2.version}
    
     
    
      org.projectlombok
      lombok
      ${lombok.version}
      provided
    
    
    
      com.github.pagehelper
      pagehelper
      5.1.2
    
  

  
    mybatis01
    
      
        org.apache.maven.plugins
        maven-compiler-plugin
        3.7.0
        
          ${maven.compiler.source}
          ${maven.compiler.target}
          ${project.build.sourceEncoding}
        
      
      
      
      
        org.mybatis.generator
        mybatis-generator-maven-plugin
        1.3.2
        
          
            mysql
            mysql-connector-java
            ${mysql.version}
          
        
        
          true
        
      
    
  

2. 将pagehelper插件配置到mybatis中

   
       
       

例如:我的mybatis.cfg..xml文件




    
    

    
    
        
        
    

    
   


    
        
        
    


    
    
        
            
            

            
            
            
            
            
            
                
                
                
                
            
        
    

 
        
    

3.导入pageBean文件在util包下

package com.zking.util;

import java.io.Serializable;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

public class PageBean implements Serializable {

	private static final long serialVersionUID = 2422581023658455731L;

	//页码
	private int page=1;
	//每页显示记录数
	private int rows=10;
	//总记录数
	private int total=0;
	//是否分页
	private boolean isPagination=true;
	//上一次的请求路径
	private String url;
	//获取所有的请求参数
	private Map map;
	
	public PageBean() {
		super();
	}
	
	//设置请求参数
	public void setRequest(HttpServletRequest req) {
		String page=req.getParameter("page");
		String rows=req.getParameter("rows");
		String pagination=req.getParameter("pagination");
		this.setPage(page);
		this.setRows(rows);
		this.setPagination(pagination);
		this.url=req.getContextPath()+req.getServletPath();
		this.map=req.getParameterMap();
	}
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Map getMap() {
		return map;
	}

	public void setMap(Map map) {
		this.map = map;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}
	
	public void setPage(String page) {
		if(null!=page&&!"".equals(page.trim()))
			this.page = Integer.parseInt(page);
	}

	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}
	
	public void setRows(String rows) {
		if(null!=rows&&!"".equals(rows.trim()))
			this.rows = Integer.parseInt(rows);
	}

	public int getTotal() {
		return total;
	}

	public void setTotal(int total) {
		this.total = total;
	}
	
	public void setTotal(String total) {
		this.total = Integer.parseInt(total);
	}

	public boolean isPagination() {
		return isPagination;
	}
	
	public void setPagination(boolean isPagination) {
		this.isPagination = isPagination;
	}
	
	public void setPagination(String isPagination) {
		if(null!=isPagination&&!"".equals(isPagination.trim()))
			this.isPagination = Boolean.parseBoolean(isPagination);
	}
	
	/**
	 * 获取分页起始标记位置
	 * @return
	 */
	public int getStartIndex() {
		//(当前页码-1)*显示记录数
		return (this.getPage()-1)*this.rows;
	}
	
	/**
	 * 末页
	 * @return
	 */
	public int getMaxPage() {
		int totalpage=this.total/this.rows;
		if(this.total%this.rows!=0)
			totalpage++;
		return totalpage;
	}
	
	/**
	 * 下一页
	 * @return
	 */
	public int getNextPage() {
		int nextPage=this.page+1;
		if(this.page>=this.getMaxPage())
			nextPage=this.getMaxPage();
		return nextPage;
	}
	
	/**
	 * 上一页
	 * @return
	 */
	public int getPreivousPage() {
		int previousPage=this.page-1;
		if(previousPage<1)
			previousPage=1;
		return previousPage;
	}

	@Override
	public String toString() {
		return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", isPagination=" + isPagination
				+ "]";
	}
}

4.在BookMapper类定义方法

 //分页查询
    List queryBookPager(Book book, PageBean pageBean);

5.在BookMapper.xml文件中进行sql语句的编写

  @Override
    public List queryBookPager(Book book, PageBean pageBean) {
        return bookMapper.queryBookPager(book);
    }

6.在iBookService类编写代码

 //分页查询
    List queryBookPager(Book book, PageBean pageBean);

7.实现接口所定义的方法

 @Override
    public List queryBookPager(Book book, PageBean pageBean) {
        return bookMapper.queryBookPager(book);
    }

8.在你需要进行分页的Mybatis方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个Mybatis查询方法会被进行分页

  //设置分页处理
       if (null != pageBean && pageBean.isPaginate()) {
         PageHelper.startPage(pageBean.getCurPage(), pageBean.getPageRecord());
       }
       

9. 获取分页信息(二种方式)

         ①:使用插件后,查询实际返回的是Page,而非List,Page继承了ArrayList,同时还包含分页相关的信息

 Page page = (Page)list;
          System.out.println("页码:" + page.getPageNum());
          System.out.println("页大小:" + page.getPageSize());
          System.out.println("总记录:" + page.getTotal());

   ②:使用PageInfo

 PageInfo pageInfo = new PageInfo(list);
          System.out.println("页码:" + pageInfo.getPageNum());
          System.out.println("页大小:" + pageInfo.getPageSize());
          System.out.println("总记录:" + pageInfo.getTotal());

  我的分页获取信息,使用第二种方式:

 @Test
   //分页查询
   public  void queryBookPager(){
       PageBean pageBean=new PageBean();
       //判断是否分页
       if(null!=pageBean&&pageBean.isPagination())
           //pageBean.getPage()---当前页数
           //pageBean.getRows()----每页条数
           PageHelper.startPage(pageBean.getPage(),pageBean.getRows());
       List bookList = iBookService.queryBookPager(Book.builder().build(), pageBean);
       System.out.println(bookList.getClass());

       if(null!=pageBean&&pageBean.isPagination()) {
           PageInfo pageInfo = new PageInfo(bookList);
           System.out.println("页码:" + pageInfo.getPageNum());
           System.out.println("页大小:" + pageInfo.getPageSize());
           System.out.println("总记录:" + pageInfo.getTotal());
           List list = pageInfo.getList();
           list.forEach(System.out::println);
       }
   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第33张图片

 

查看sql语句:

Mybatis 快速入门之 动态sql和分页_第34张图片

 

六:特殊字符处理

特殊字符相关属性
> >
< <
& &
空格  ;

问题:为什么需要转义?

答:因为在mybatis中的sql语句是写在xml文件中的,但是在处理范围查询的时候经常要用到<,>,$等特殊字符

案例:价格范围查询

①:定义一个特殊类,用来存放范围值

package com.zking.vo;

import com.zking.model.Book;
import lombok.Data;

import java.util.List;

/**
 * @author 唐渊
 * @create  2022-07-23 9:26
 */
@Data //getter/setter/toString
public class BookVo extends Book {
     //最小价格
    private Integer min;
    //最大价格
    private  Integer max;



}

②:在BookMapper类定义方法

//范围查询,转义字符处理
     List queryBookRange(BookVo bookVo);

③:在BookMapper.xml文件中进行sql语句的编写

④:在iBookService类编写代码

//范围查询,转义字符处理
    List queryBookRange(BookVo bookVo);

⑤:实现接口所定义的方法

 @Override
    public List queryBookRange(BookVo bookVo) {
        return bookMapper.queryBookRange(bookVo);
    }

⑥:进行 junit4单元测试

 @Test
    //范围查询,转义字符处理
    public void  queryBookRange(){
        BookVo bookVo=new BookVo();
        bookVo.setMin(50);
        bookVo.setMax(200);
        List books = iBookService.queryBookRange(bookVo);
        //不使用转义字符前
        //元素内容必须由格式正确的字符数据或标记组成。
        books.forEach(System.out::println);
    }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第35张图片

 

查看sql语句:

 

七:批量新增

        mybatis原则上是不能够一次批量执行多条SQL语句,比如新增、删除、更新等,但是修改jdbc url连接带参数可以实现相同效果

spring:
  datasource:
    username: root
    password: mysql
    # allowMultiQueries 是否允许一条SQL语句包含多个执行SQL以分号;分隔
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&allowMultiQueries=true
    driver-class-name: com.mysql.cj.jdbc.Driver

重点:

        allowMultiQueries=true 允许一条SQL语句包含多个执行SQL以分号;分隔,是必须添加的

①:在BookMapper类定义方法

//批量新增
    int insertBatch(List list);

②:在BookMapper.xml文件中进行sql语句的编写

 
    insert into t_book ( bname,bprice,btype ) values
    
      (#{it.bname},#{it.bprice},#{it.btype})
    
  

③:在iBookService类编写代码

  //批量新增
    int insertBatch(List list);

④:实现接口所定义的方法

 @Override
    public int insertBatch(List list) {
        return bookMapper.insertBatch(list);
    }

⑤:进行 junit4单元测试

@Test
  //批量新增
    public void  insertBatch(){
      List list = new ArrayList<>();
      book.setBname("西罗马帝国");
      book.setBprice(34);
      book.setBtype("历史");
      list.add(book);
      book.setBname("世界大战一");
      book.setBprice(65);
      book.setBtype("历史");
      list.add(book);
      int i = iBookService.insertBatch(list);
      if (i>0) {
          System.out.println("yes");
      }

  }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第36张图片

查看sql语句:

 

八:批量更新

①:在BookMapper类定义方法

 //批量更新
    int updateForNew(List List);

②:在BookMapper.xml文件中进行sql语句的编写

 
    insert into t_book (bname,bprice,btype) values
    
      (#{it.bname},#{it.bprice},#{it.btype})
    
    on duplicate key update bname=values(bname);
  

③:在iBookService类编写代码

 @Override
   int updateForNew(List List) ;
   

④:实现接口所定义的方法

 @Override
    public int updateForNew(List list) {
        return bookMapper.insertBatch(list);
    }

⑤:进行 junit4单元测试

@Test
   //批量更新
    public void updateForNew(){
       List list = new ArrayList();
       book.setBname("上帝之鞭");
       book.setBprice(56);
       book.setBtype("历史");
       list.add(book);
       book.setBname("西楚霸王");
       book.setBprice(77);
       book.setBtype("历史");
       list.add(book);
       int i = iBookService.updateForNew(list);
       if (i>0) {
           System.out.println("yes");
       }
}

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第37张图片

九:批量删除

①:在BookMapper类定义方法

   //批量删除
    int deleteBatch(List idList);

②:在BookMapper.xml文件中进行sql语句的编写


    delete from t_book where bid in
    
      #{it}
    
  

③:在iBookService类编写代码

 //批量删除
    int deleteBatch(List idList);

④:实现接口所定义的方法

 @Override
    public int deleteBatch(List idList) {
        return bookMapper.deleteBatch(idList);
    }

⑤:进行 junit4单元测试

 @Test
   //批量删除
    public  void deleteBatch(){
       List list = new ArrayList<>();
       list.add(31);
       list.add(32);
       int i = iBookService.deleteBatch(list);
       if (i>0) {
           System.out.println("yes");
       }

   }

测试结果如下:

Mybatis 快速入门之 动态sql和分页_第38张图片

 

查看sql语句:

    代码操作有点多,但全是干货

Mybatis 快速入门之 动态sql和分页_第39张图片

你可能感兴趣的:(mybatis,mybatis,sql,java)