目录
一:动态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操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况;
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);
}
查看sql语句:
---测试不type类型的查询:
@Test
//mybatis之if标签
public void queryBookByIf(){
List bookList = iBookService.queryBookByIf(Book.builder().build());
bookList.forEach(System.out::println);
}
测试结果如下:
查看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);
}
测试结果如下:
查看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);
}
测试结果如下:
查看sql语句:
------测试带type类型的查询:
@Test
//choose 标签
public void queryBookByChoose(){
List books = iBookService.queryBookByChoose(Book.builder().btype("历史").build());
books.forEach(System.out::println);
}
测试结果如下:
查看sql语句:
------测试带id类型的查询:
@Test
//choose 标签
public void queryBookByChoose(){
List books = iBookService.queryBookByChoose(Book.builder().bid(30).build());
books.forEach(System.out::println);
}
测试结果如下:
查看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);
}
测试结果如下:
查看sql语句:
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);
}
测试结果如下:
查看sql语句:
------测试带type类型的查询:
@Test
//where标签
public void queryBookWhere(){
List books = iBookService.queryBookWhere(Book.builder().btype("文学").build());
books.forEach(System.out::println);
}
测试结果如下:
查看sql语句:
①:案例演示: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);
}
测试结果如下:
查看sql语句:
ok,不带id参数的测试,通过sql语句可以看出来,相当于查询所有,那么我们再来进行带id参数的测试:
@Test
public void queryBookByInteger(){
List books = iBookService.queryBookByInteger(3);
books.forEach(System.out::println);
}
测试结果如下:
很好,出现了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}
继续测试,看效果,查看是否可以运行:
查看sql语句:
OK,nice,将xml文件在的bid全部转换为value(注意:数据库的字段除外),来继续尝试:
and bid=#{value}
测试结果如下:
查看sql语句:
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);
}
测试结果如下:
报错提示:
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}
好,继续运行,看看结果:
报错提示:
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}
测试结果如下:
OK,还是在报我们第一次运行时的错误,一直在报错,这就告诉我们String类型的传参不能这么直接传参,还需要额外的参数,那么我们将BookMapper类的方法用注解的方法进行额外的设参,用@param()的方式进行设参,例如我的String类型的传递参数问题解决方案如下:
//bookType-->参数
//btype-->变量名
List queryBookByString(@Param("bookType") String btype);
mapper的映射文件如老样子,不进行修改,进行运行,看是否会报错
and btype=#{value}
测试结果如下:
报错提示:
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}
测试结果如下:
好,传递String类型的参数的bug终于解决掉了,当我们遇到bug时,不要放弃,要大胆尝试,从另一个方向分析出发,可能会有意外的收获
①:在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);
}
测试结果如下:
查看sql语句:
①:在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);
}
测试结果如下:
查看sql语句:
①:在BookMapper类定义方法
List queryBookLike(Book book);
②:在BookMapper.xml文件中进行sql语句的编写
③:在iBookService类编写代码
//模糊查询
List queryBookLike(Book book);
④:实现接口所定义的方法
@Override
public List queryBookLike(Book book) {
return bookMapper.queryBookLike(book);
}
重点:相当于占位符,参数传递时需要手动拼接%%百分号 例如:"zs"-->'zs' 会自动拼接单引号
⑤:进行 junit4单元测试
方式一:使用${}方式进行模糊查询
@Test
//模糊查询
public void queryBookLike(){
List books = iBookService.queryBookLike(Book.builder().bname("%与%").build());
books.forEach(System.out::println);
}
测试结果如下:
查看sql语句:
重点:使用$传递参数时,只会传递参数本身--->例如:"zs"-->zs 不会自动拼接单引号
⑤:进行 junit4单元测试
方式二:使用#{}方式进行模糊查询
@Test
//模糊查询
public void queryBookLike(){
List books = iBookService.queryBookLike(Book.builder().bname("与").build());
books.forEach(System.out::println);
}
测试结果如下:
and bname like '%${bname}%'
查看sql语句:
⑤:进行 junit4单元测试
方式三:使用concat()方式进行模糊查询
and bname like concat('%',#{bname},'%')
测试结果如下:
查看sql语句:
答:参数类型为字符串,#会在前后加单引号['],$则直接插入值
数据库要执行 SQL 访问数据,数据库是个执行机构,它只会检查传来的 SQL 是不是合乎语法,而并不会关心这个语句是否会造成伤害(数据泄露或破坏)。正因为只要符合语法规则就会执行的机制,导致 SQL 有了注入的风险。
SQL 本身就是个字符串,而且一般没有加密,字符串可能被黑客劫持修改,这样就可能造成数据库执行了不该执行的动作。
SQL 注入的惯用做法是通过把 SQL 子串插入到 Web 表单项或页面请求(Url)的查询字符串中提交,最终达到欺骗服务器执行恶意操作的目的。
常见案例包括通过植入 SQL 骗过登录验证。而之前很多影视网站泄露 VIP 会员密码的事件,很多就是通过 SQL 植入到 WEB 表单暴露的,并且这类表单特别容易受到攻击。通过 SQL 植入,不仅可以非法获取账号信息,严重的还能够篡改、删除重要数据信息。
返回结果集的类型:
(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);
}
测试结果如下:
查看sql语句:
(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);
}
测试结果如下:
查看sql语句:
(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);
}
测试结果如下:
查看sql语句:
(1):在BookMapper类定义方法
List
(2):在BookMapper.xml文件中进行sql语句的编写
(3):在iBookService类编写代码
List
(4):实现接口所定义的方法
@Override
public List
(5):进行 junit4单元测试
@Test
//List
测试结果如下:
查看sql语句:
实现分页查询的步骤:
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.target}
${project.build.sourceEncoding}
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.2
mysql
mysql-connector-java
${mysql.version}
true
例如:我的mybatis.cfg..xml文件
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
+ "]";
}
}
//分页查询
List queryBookPager(Book book, PageBean pageBean);
@Override
public List queryBookPager(Book book, PageBean pageBean) {
return bookMapper.queryBookPager(book);
}
//分页查询
List queryBookPager(Book book, PageBean pageBean);
@Override
public List queryBookPager(Book book, PageBean pageBean) {
return bookMapper.queryBookPager(book);
}
//设置分页处理
if (null != pageBean && pageBean.isPaginate()) {
PageHelper.startPage(pageBean.getCurPage(), pageBean.getPageRecord());
}
①:使用插件后,查询实际返回的是Page
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);
}
}
测试结果如下:
查看sql语句:
> | > |
< | < |
& | & |
空格 |  ; |
问题:为什么需要转义?
答:因为在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);
}
测试结果如下:
查看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");
}
}
测试结果如下:
查看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");
}
}
测试结果如下:
九:批量删除
①:在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");
}
}
测试结果如下:
查看sql语句:
代码操作有点多,但全是干货