前言
在前面的一期博客中我们分享了有关Mybatis入门简介及用Mybatis模拟测试一些相关数据库数据操作的功能,这一期博客我继续为大家分享有关Mybatis的相关知识点,今天我分享的内容是Mybatis之动态SQL及映射结果。请老铁们仔细阅读。
一、Mybatis之动态SQL
1. 简介
- MyBatis中的动态SQL是一种在SQL语句中根据条件动态生成不同部分的技术。它允许我们根据不同的条件来构建不同的SQL语句,从而实现更灵活的查询和更新操作。
- 在MyBatis中,我们可以使用动态SQL来处理各种情况,例如根据不同的条件拼接WHERE子句、根据条件选择不同的列、根据条件判断是否包含某个元素等等。
- MyBatis提供了一些标签和函数来实现动态SQL,其中最常用的是if、choose、when、otherwise和foreach标签。通过使用这些标签,我们可以根据条件来动态生成SQL语句的不同部分。
2. 作用及重要性
- 生成SQL语句具有灵活性:动态SQL允许根据不同的条件来生成不同的SQL语句,从而实现动态查询和更新操作。这样我们可以根据项目框架需求灵活地构造所需的SQL语句,避免了不需要硬编码的情况出现。
- 使SQL语句清晰易懂(可读性):使用动态SQL可以使SQL语句更加清晰易读。通过使用内置携带的函数与标签,根据条件组织SQL语句的不同部分,从而避免大量的SQL嵌套与重复。它使SQL语句更加直观,更有利于开发人员理解及维护。
- 具有较强的扩展性:动态SQL提供了一种扩展SQL语句的方式,允许我们根据需求加、修改或删除查询条件。这种扩展性使得我们能够轻松地改变和优化SQL语句,而不需要修改大量的固定SQL代码。这样大大减少了开发使用的时间,提高了开发效率及后期的维护效率。
- 性能优化:通过使用动态SQL,我们可以根据不同的条件动态生成SQL语句,从而避免不必要的查询或更新操作。例如,我们可以根据用户的选择动态生成查询条件, 只查询真正需要的数据,减少了不必要的数据库操作,提高了系统性能。
3. 应用场景
Mybatis的应用场景
应用场景 | 说明 |
条件查询 | 当需要根据不同的条件进行查询时,可以使用动态SQL来根据条件动态拼接WHERE子句。比如在一个用户管理系统中,可以根据用户的姓名、性别、年龄等条件来进行灵活的查询。 |
动态排序 | 当需要根据不同的字段进行排序时,可以使用动态SQL来动态生成ORDER BY子句。比如在一个商品列表中,用户可以选择按照价格、销量等字段进行排序。 |
动态更新 | 当需要根据不同的条件来进行更新操作时,可以使用动态SQL来根据条件动态生成UPDATE语句。比如在一个订单系统中,可以根据订单状态、支付状态等条件来更新订单信息。 |
动态插入 | 当需要根据不同的条件来进行插入操作时,可以使用动态SQL来根据条件动态生成INSERT语句。比如在一个用户注册系统中,可以根据用户的选择来插入不同的用户信息。 |
复杂逻辑处理 | 当需要根据复杂的业务逻辑来生成SQL语句时,可以使用动态SQL来处理复杂的逻辑判断和条件拼接。比如在一个电商系统中,根据不同的促销活动和用户等级来生成不同的优惠查询条件。 |
批量操作 | 当需要对多个对象进行批量操作时,可以使用动态SQL来生成批量操作的SQL语句。比如批量插入多个用户数据或批量删除多个订单数据。 |
二、动态SQL讲解
1. 原生使用工具类(BaseDao)的SQL
//模拟原生编写数据库访问方法 BaseDao.java excuteUpdate(sql,book,attrs) String sql=update t_mvc_book set bname =?,price = ? where bid =? // 此时假如前台jsp传参到后台,没有传递bname值,那么造成的结果如下 update t_mvc_book set bname =null price =33 where bid =3
弊端:会将没有传参的字段值改为null,违背了我们编码的初衷。
2. 运用动态SQL编写方法
2.1 Mybatis动态SQL的常用标签
常用标签
标签 | 使用说明 |
<if> | 条件判断标签,根据指定的条件来决定是否生成对应的SQL语句片段 |
<choose> 、<when> 、<otherwise> |
类似于Java中的switch语句,根据不同的条件来选择生成不同的SQL语句片段。 |
<trim> | 用于去除或补齐SQL语句片段的开头和结尾的空格,可以用于拼接包含可选条件的SQL语句。 |
<where> | 用于拼接WHERE子句,自动处理WHERE关键字和添加适当的AND或OR连接条件。 |
<set> | 用于拼接UPDATE语句的SET子句,自动处理SET关键字和添加适当的逗号分隔更新字段。 |
<foreach> | 用于循环遍历集合或数组,并在SQL语句中插入对应的元素作为参数。可以指定开始位置、结束位置、分隔符等属性。 |
<bind> | 用于将一个常量绑定到一个变量上,在后续的SQL语句中使用该变量。 这些标签在Mybatis中可以帮助我们根据不同的条件动态生成SQL语句,使得我们可以更加灵活地构建查询和更新语句。 |
2.2 Mybatis动态SQL的常用函数
常用函数
函数 | 函数说明 |
trim() | 去除字符串的开头或结尾指定字符(默认为空格)。 例子:<trim prefixOverrides="AND |OR ">...</trim> |
concat() | 拼接多个字符串。 例子:${param1} + ' ' + ${param2} |
substring() | 截取字符串的一部分。 例子:SUBSTRING(column_name, start_index, length) |
lower() | 将字符串转换为小写。 例子:LOWER(column_name) |
upper() | 将字符串转换为大写。 例子:UPPER(column_name) |
replace() | 替换字符串中的某个字符或字符串。 例子:REPLACE(column_name, old_string, new_string) |
length() | 获取字符串的长度。 例子:LENGTH(column_name) |
now() | 获取当前时间。 例子:NOW() |
date_format() | 格式化日期。 例子:DATE_FORMAT(column_name, pattern) |
2.3 案例展示
if标签的运用
foreach标签的运用
场景
//假设编写的SQL语句如下所示 delete* from t_oa_permission where id in (...) //其中括号里的是条件,也是前台需要传过来的参数 //有些时候我们前台会传一个字符串过来(如下所示) 1,2,3,4,5,6 //像我们在删除购物车的时候,我们一般会这样写 for int id : ids orderItemsDao.delete(id); //这么写的目的只是懒得拼接SQL语句 delete* from t_oa_permission where id in ( 1,2,3,4,5,6) // 如果我们要上上面那样去编写代码的话 // 首先实例化Stringbuffer类来读取字符串 Stringbuffer sb=new Stringbuffer(); // 然后对其进行一系列操作 sb.append(",").append(id) //进行选择性的截取 sb.substring(1) //由此而知,我们如果按照上述方式编写代码的话会需要花费人力资源和时间精力, //这并不利于我们大大提高我们自身的开发效率; //而且该方式对SQL语句处理较为复杂,过程繁琐。
BookMapper.xml(编写方法)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.yx.mapper.BookMapper" > <resultMap id="BaseResultMap" type="com.yx.model.Book" > <constructor > <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" /> <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" /> <arg column="price" jdbcType="REAL" javaType="java.lang.Float" /> </constructor> </resultMap> <sql id="Base_Column_List" > bid, bname, price </sql> <select id="selectByBids" resultType="com.yx.model.Book" parameterType="java.util.List" > select <include refid="Base_Column_List" /> from t_mvc_book where bid in <foreach collection="bids" item="bid" open="(" close=")" separator=","> #{bid} </foreach> </select> </mapper>
在接口类和接口实现编写方法
package com.yx.biz; import com.yx.model.Book; import java.util.List; public interface BookBiz { List<Book> selectByBids(List bids); } //========================以上是接口类的代码===================== //==========================以下是接口实现类的代码========================== package com.yx.biz.Impl; import com.yx.biz.BookBiz; import com.yx.mapper.BookMapper; import com.yx.model.Book; import java.util.List; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:15 */ public class BookBizImpl implements BookBiz { @Override public List<Book> selectByBids(List bids) { return bookMapper.selectByBids(bids); } } //==========================以下是BookMapper 的代码========================== package com.yx.mapper; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BookMapper { List<Book> selectByBids(@Param("bids") List bids); }
测试类代码
@Test // 测试方法 public void testByid(){ System.out.println("测试使用foreach标签的方法..."); List<Integer> bids = Arrays.asList(new Integer[]{55, 56, 57, 58, 59, 60}); bookBiz.selectByBids(bids).forEach(System.out::println);//jdk1.8的新特性。 // 打印输出 }
输出结果
三、动态SQL之模糊查询
1. 模糊查询的三种写法
BookMapper.xm
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.yx.mapper.BookMapper" > <resultMap id="BaseResultMap" type="com.yx.model.Book" > <constructor > <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" /> <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" /> <arg column="price" jdbcType="REAL" javaType="java.lang.Float" /> </constructor> </resultMap> <sql id="Base_Column_List" > bid, bname, price </sql> <!-- #字符号--> <select id="like01" resultType="com.yx.model.Book" parameterType="java.lang.String"> select <include refid="Base_Column_List" /> from t_mvc_book where bname like #{bname} </select> <!-- $符号--> <select id="like02" resultType="com.yx.model.Book" parameterType="java.lang.String"> select <include refid="Base_Column_List" /> from t_mvc_book where bname like ${bname} </select> <!-- concat--> <select id="like03" resultType="com.yx.model.Book" parameterType="java.lang.String"> select <include refid="Base_Column_List" /> from t_mvc_book where bname like concat('%',#{bname},'%') </select> </mapper>
在接口类和接口实现编写方法
package com.yx.mapper; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BookMapper { //# List<Book> like01(@Param("bname") String bname); //$ List<Book> like02(@Param("bname") String bname); //concat List<Book> like03(@Param("bname") String bname); } //===============以上是BookMapper的代码======================== //===============以下是方法接口的代码======================== package com.yx.biz; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BookBiz { //# List<Book> like01(@Param("bname") String bname); //$ List<Book> like02(@Param("bname") String bname); //concat List<Book> like03(@Param("bname") String bname); } //===============以下是方法接口实现类的代码======================== package com.yx.biz.Impl; import com.yx.biz.BookBiz; import com.yx.mapper.BookMapper; import com.yx.model.Book; import java.util.List; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:15 */ public class BookBizImpl implements BookBiz { // 调用代码生成器的接口 BookMapper bookMapper; public BookMapper getBookMapper() { return bookMapper; } public void setBookMapper(BookMapper bookMapper) { this.bookMapper = bookMapper; } @Override public List<Book> like01(String bname) { return bookMapper.like01(bname); } @Override public List<Book> like02(String bname) { return bookMapper.like02(bname); } @Override public List<Book> like03(String bname) { return bookMapper.like03(bname); } }
测试类代码
package com.yx.Demo; import com.yx.biz.BookBiz; import com.yx.biz.Impl.BookBizImpl; import com.yx.mapper.BookMapper; import com.yx.model.Book; import com.yx.untils.SessionUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.List; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:26 * 测试增删改查的方法 */ public class Dmeo1 { // 实例化工具类和业务层类 private SqlSession sqlSession; private BookBiz bookBiz; @Before public void a(){ System.out.println("执行测试代码块之前会执行的初始化代码块......"); // 获取session对象 sqlSession=SessionUtil.openSession(); BookBizImpl bookBiz=new BookBizImpl(); // 获取BookMapper对象 BookMapper mapper=sqlSession.getMapper(BookMapper.class); // 将获取到的BookMapper对象添加到bookBiz中 bookBiz.setBookMapper(mapper); // 扩大作用权限 this.bookBiz=bookBiz; } @After public void b(){ System.out.println("执行测试代码块之后会执行的初始化代码块......"); // 提交数据库提交事务 sqlSession.commit(); } @Test // 测试方法 public void testlike01(){ System.out.println("测试like01方法..."); bookBiz.like01("%圣墟%").forEach(System.out::println);//jdk1.8的新特性。 } @Test // 测试方法 public void testlike02(){ System.out.println("测试like01方法..."); bookBiz.like02("%圣墟%").forEach(System.out::println);//jdk1.8的新特性。 } @Test // 测试方法 public void testlike03(){ System.out.println("测试like01方法..."); bookBiz.like03("%圣墟%").forEach(System.out::println);//jdk1.8的新特性。 } }
测试结果
#字符编写方法的测试效果
$字符编写方法的测试效果
运用concat编写的方法测试结果
注意事项:
- 如果运用了$字符编写了模糊查询的方法,在方法语句体中${参数字段}未用单引号包裹则会报错,SQL编写错误如下图所示
2.#符和$符的区别(面试题)
- $是占位符传参,#是预处理SQL
- 在外在形式,$传参不带引号,#传参自带引号
- $传参存在SQL注入,#不存在
- $可以用来做动态列,完成动态SQL开发
四、Mybatis中的结果映射
使用mybatis的各种场景,返回的结果是多样的,resultType与resultMap有什么区别 请看下面模拟。
(1)场景模拟及使用的结果映射
1.返回单表的对应的实体类,仅又一个查询结果(可以用resultType/resultMap)
2.返回单表的对应的实体类,有多个查询结果(可以用resultType/resultMap)
3.返回多表的对应结果,仅有一个查询结果(通常用resultType,也可以用resultMap)
4.返回多表的对应结果,有多个查询结果(通常用resultType,也可以用resultMap)
5.返回单个列段,仅有一个查询结果(就用resultType)
6.返回单个列段,有多个查询结果(就用resultType)
(2)resultType与resultMap的区别
- resultType:对应的是返回类型
- resultMap:对应的是返回映射关系,指的是实体类与数据库表字段的关系。
通常而言,单表查询,返回单列,返回多表查询结果,使用resultType。
如果查询的结果,需要使用关联属性的体现,那么使用resultMap。
resultType适用于简单的映射需求,而resultMap适用于更复杂的映射需求,可以定义更灵活的映射规则。根据具体的需求和情况,选择合适的映射方式非常重要。
五、Mybatis编写分页查询SQL
1.为什么重写Mybatis的分页
Mybatis的分页功能很弱,它是基于内存的分页(查询所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没用的。主要原因如下所示:
- 自定义功能需求:Mybatis的默认分页插件可能无法满足特定的分页需求,比如定制化的分页逻辑、特殊的排序方式等。重写分页可以根据具体需求进行个性化的扩展和优化。
- 性能优化:Mybatis的默认分页插件在处理大数据量时可能存在性能瓶颈,重写分页可以通过优化算法、减少数据库查询次数等方式提升性能。
- 适应新版本:Mybatis框架本身不断更新迭代,引入了新的特性和改进,原有的分页插件可能不再兼容或不充分利用新版本的特性。重写分页可以更新适应新版本的Mybatis框架。
- 深入理解分页原理:通过重写分页,可以更深入地理解分页机制的原理和实现方式,加深对持久层框架的理解和掌握。
2. 不使用分页插件编写的分页SQL
BookMapper.xml(SQL代码编写)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.yx.mapper.BookMapper" > <resultMap id="BaseResultMap" type="com.yx.model.Book" > <constructor > <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" /> <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" /> <arg column="price" jdbcType="REAL" javaType="java.lang.Float" /> </constructor> </resultMap> <sql id="Base_Column_List" > bid, bname, price </sql> <select id="page" resultType="com.yx.model.Book" parameterType="java.util.Map"> select <include refid="Base_Column_List" /> from t_mvc_book where bname like #{bname} limit #{start},#{end} </select> </mapper>
BookMapper.java(代码编写)
package com.yx.mapper; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; public interface BookMapper { List<Book> page(Map map); }
接口类和接口实现类(代码编写)
package com.yx.biz; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; List<Book> page(Map map); } //=================以上是接口类的代码============================== //=================以下是接口实现类的代码=========================== package com.yx.biz.Impl; import com.yx.biz.BookBiz; import com.yx.mapper.BookMapper; import com.yx.model.Book; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:15 */ public class BookBizImpl implements BookBiz { // 调用代码生成器的接口 BookMapper bookMapper; public BookMapper getBookMapper() { return bookMapper; } public void setBookMapper(BookMapper bookMapper) { this.bookMapper = bookMapper; } @Override public List<Book> page(Map map) { return bookMapper.page(map); } }
测试类测试代码
package com.yx.Demo; import com.yx.biz.BookBiz; import com.yx.biz.Impl.BookBizImpl; import com.yx.mapper.BookMapper; import com.yx.model.Book; import com.yx.untils.SessionUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:26 * 测试增删改查的方法 */ public class Dmeo1 { // 实例化工具类和业务层类 private SqlSession sqlSession; private BookBiz bookBiz; @Before public void a(){ System.out.println("执行测试代码块之前会执行的初始化代码块......"); // 获取session对象 sqlSession=SessionUtil.openSession(); BookBizImpl bookBiz=new BookBizImpl(); // 获取BookMapper对象 BookMapper mapper=sqlSession.getMapper(BookMapper.class); // 将获取到的BookMapper对象添加到bookBiz中 bookBiz.setBookMapper(mapper); // 扩大作用权限 this.bookBiz=bookBiz; } @After public void b(){ System.out.println("执行测试代码块之后会执行的初始化代码块......"); // 提交数据库提交事务 sqlSession.commit(); } @Test// 测试方法 public void testpage(){ System.out.println("测试分页方法...(未使用插件)"); // 实例化一个Map集合用来存储方法参数 Map map=new HashMap<>(); // 将参数一一对应加入集合中 map.put("bname","%圣墟%");//模糊查询的关键字段 map.put("start",2);//开始查询的页数 map.put("size",10); // 调用方法 bookBiz.page(map).forEach(System.out::println); } }
测试结果(如图示)
注意事项:
- 在BookMapper.xml中编写SQL语句时,携带的参数个数发生改变,则参数的类型也要进行对应的改变。
- 在调用方法时,记得将参数定义好封装到对应的结合中,再将集合作为参数放到方法中。
- 该方式编写分页SQL语句需要在每一个方法中编写类似like #{bname} limit #{start},#{size}
的代码,因此增加的代码的重复多余。
3. 使用分页插件编写分页SQL
3.1 导入插件相关的pom.xml依赖
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.2</version> </dependency>
3.2 Mybatis.cfg.xml配置拦截器
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
在Mybatis.cfg.xml添加上述代码,这是配置拦截器,当然添加的位置不能随意,一定要在environments标签的前面,否则将会报错,无法配置使用。
3.3 使用PageHelper进行分页
加载分页工具类(PageBean)
package com.yx.untils; import javax.servlet.http.HttpServletRequest; import java.io.Serializable; import java.util.Map; 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<String,String[]> 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<String, String[]> getMap() { return map; } public void setMap(Map<String, String[]> 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 + "]"; } }
BookMapper.java、接口类机接口实现类编写方法
package com.yx.mapper; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; public interface BookMapper { List<Book> likepage(@Param("bname") String bname); } //======================以上是BookMapper.java代码============================ //======================以下是接口类代码===================================== package com.yx.biz; import com.yx.model.Book; import com.yx.untils.PageBean; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; public interface BookBiz { List<Book> likepage(String bname, PageBean pagebean); } //======================以下是接口类实现类代码===================================== package com.yx.biz.Impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.yx.biz.BookBiz; import com.yx.mapper.BookMapper; import com.yx.model.Book; import com.yx.untils.PageBean; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:15 */ public class BookBizImpl implements BookBiz { // 调用代码生成器的接口 BookMapper bookMapper; public BookMapper getBookMapper() { return bookMapper; } public void setBookMapper(BookMapper bookMapper) { this.bookMapper = bookMapper; } @Override public List<Book> likepage(String bname, PageBean pagebean) { if(pagebean !=null && pagebean.isPagination()){//pagebean是不为空并且打开分页功能 PageHelper.startPage(pagebean.getPage(),pagebean.getRows()); } List<Book> books=bookMapper.likepage(bname); if (pagebean !=null && pagebean.isPagination()) { PageInfo<Book> info=new PageInfo<>(books); System.out.println("当前页:" + info.getPageNum()); System.out.println("展示记录数:" + info.getPageSize()); System.out.println("符合查询条件的总记录数:" + info.getTotal()); pagebean.setTotal((int) info.getTotal()); } return books; } }
测试类代码
package com.yx.Demo; import com.yx.biz.BookBiz; import com.yx.biz.Impl.BookBizImpl; import com.yx.mapper.BookMapper; import com.yx.model.Book; import com.yx.untils.PageBean; import com.yx.untils.SessionUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:26 * 测试增删改查的方法 */ public class Dmeo1 { // 实例化工具类和业务层类 private SqlSession sqlSession; private BookBiz bookBiz; @Before public void a(){ System.out.println("执行测试代码块之前会执行的初始化代码块......"); // 获取session对象 sqlSession=SessionUtil.openSession(); BookBizImpl bookBiz=new BookBizImpl(); // 获取BookMapper对象 BookMapper mapper=sqlSession.getMapper(BookMapper.class); // 将获取到的BookMapper对象添加到bookBiz中 bookBiz.setBookMapper(mapper); // 扩大作用权限 this.bookBiz=bookBiz; } @After public void b(){ System.out.println("执行测试代码块之后会执行的初始化代码块......"); // 提交数据库提交事务 sqlSession.commit(); } @Test// 测试 public void testlikepage(){ System.out.println("测试使用插件的分页方法..."); PageBean pageBean=new PageBean(); pageBean.setPage(2);//设置查询的页数 pageBean.setRows(10);//设置每页显示的页数 bookBiz.likepage("圣墟",pageBean).forEach(System.out::println);//jdk1.8的新特性。 } }
测试结果
3.4 优化趋向
如上图所示,每当我们对一个实体类的查询进行分页时都要在方法中进行上述代码的编写,假如后面有商品表、订单表、订单详情表等等,我们每一个实体类的分页方法都要写一边上述代码,导致一些代码重复。因此我们可以将上述代码封装到我们的环绕通知中。
六、Mybatis的特殊字符
在Mybatis中,有一些特殊字符用于在Mapper XML文件中表示特定的含义或执行特定的操作。
扩展
pojo/entity/model:描述数据库表对应的实体类。
vo: view object 视图对象:专门用来展示的。
dto:接受参数的。
1. 特殊字符
Mybatis的特殊字符
字符 | 说明 |
# | 在Mybatis的Mapper XML文件中,# 用于处理占位符的替换。当使用 # 时,会将传入的参数值作为字符串直接替换到SQL语句中。 |
$ | 在Mybatis的Mapper XML文件中,$ 用于处理变量的替换。当使用 $ 时,会将传入的参数值直接替换到SQL语句中,不进行类型转换或预处理。 |
<![CDATA[ ]]> | <![CDATA[ ]]> 用于包裹SQL语句的内容,使其中的特殊字符和转义序列不被解析。在CDATA块中,可以直接使用特殊字符(如 < , > , & , ' 和 " )而无需进行转义。 |
${} | 在Mybatis的Mapper XML文件中,${} 用于在SQL语句中引用参数或表达式。使用${} 时,参数值会作为字符串替换到SQL语句中。 |
< 和 > |
这是HTML实体编码,用于表示小于号(< )和大于号(> ),在Mybatis的Mapper XML文件中,如果要在XML中直接使用小于号或大于号,可以使用这两个实体编码。 |
2. <![CDATA[ ]]>的使用
BookMapper.xml编写方法
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.yx.mapper.BookMapper" > <resultMap id="BaseResultMap" type="com.yx.model.Book" > <constructor > <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" /> <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" /> <arg column="price" jdbcType="REAL" javaType="java.lang.Float" /> </constructor> </resultMap> <sql id="Base_Column_List" > bid, bname, price </sql> <select id="QueryMaxMin" resultType="com.yx.model.Book" parameterType="com.yx.dto.BookDto"> select <include refid="Base_Column_List" /> from t_mvc_book where <![CDATA[ price < #{max} and price > #{min} ]]> </select> </mapper>
注:如果方法不使用<![CDATA[ ]]>特殊字符,如下面那样编写则运行测试该方法会报错。
<select id="QueryMaxMin" resultType="com.yx.model.Book" parameterType="com.yx.dto.BookDto"> select <include refid="Base_Column_List" /> from t_mvc_book where price < #{max} and price > #{min} </select>
控制台输出结果
BookDto类接受参数
package com.yx.dto; import com.yx.model.Book; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-24 16:41 */ public class BookDto extends Book { // 定义你需要的属性 private float min;//最低价格 private float max;//最高价格 public float getMin() { return min; } public void setMin(float min) { this.min = min; } public float getMax() { return max; } public void setMax(float max) { this.max = max; } }
BookMapper.java、接口类及接口实现类代码
package com.yx.mapper; import com.yx.dto.BookDto; import com.yx.model.Book; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; public interface BookMapper { List<Book> QueryMaxMin(BookDto bookDto); } //=======================以上是BookMapper代码======================================== //=======================以下是接口类代码=========================================== package com.yx.biz; import com.yx.dto.BookDto; import com.yx.model.Book; import com.yx.untils.PageBean; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; public interface BookBiz { List<Book> QueryMaxMin(BookDto bookDto); } //=======================以下是接口实现类代码=========================================== package com.yx.biz.Impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.yx.biz.BookBiz; import com.yx.dto.BookDto; import com.yx.mapper.BookMapper; import com.yx.model.Book; import com.yx.untils.PageBean; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:15 */ public class BookBizImpl implements BookBiz { // 调用代码生成器的接口 BookMapper bookMapper; public BookMapper getBookMapper() { return bookMapper; } public void setBookMapper(BookMapper bookMapper) { this.bookMapper = bookMapper; } @Override public List<Book> QueryMaxMin(BookDto bookDto) { return bookMapper.QueryMaxMin(bookDto); } }
测试类代码
package com.yx.Demo; import com.yx.biz.BookBiz; import com.yx.biz.Impl.BookBizImpl; import com.yx.dto.BookDto; import com.yx.mapper.BookMapper; import com.yx.model.Book; import com.yx.untils.PageBean; import com.yx.untils.SessionUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-21 10:26 * 测试增删改查的方法 */ public class Dmeo1 { // 实例化工具类和业务层类 private SqlSession sqlSession; private BookBiz bookBiz; @Before public void a(){ System.out.println("执行测试代码块之前会执行的初始化代码块......"); // 获取session对象 sqlSession=SessionUtil.openSession(); BookBizImpl bookBiz=new BookBizImpl(); // 获取BookMapper对象 BookMapper mapper=sqlSession.getMapper(BookMapper.class); // 将获取到的BookMapper对象添加到bookBiz中 bookBiz.setBookMapper(mapper); // 扩大作用权限 this.bookBiz=bookBiz; } @After public void b(){ System.out.println("执行测试代码块之后会执行的初始化代码块......"); // 提交数据库提交事务 sqlSession.commit(); } @Test// 测试 public void MaxMin(){ BookDto bookDto=new BookDto(); bookDto.setMin(25); bookDto.setMax(80); bookBiz.QueryMaxMin(bookDto).forEach(System.out::println);//jdk1.8的新特性。 } }
最终测结果
3.<
和 >的使用
BookMapper.xml编写方法
<select id="QueryMaxMin" resultType="com.yx.model.Book" parameterType="com.yx.dto.BookDto"> select <include refid="Base_Column_List" /> from t_mvc_book where price > #{min} and price < #{max} <!-- where <![CDATA[--> <!-- price < #{max} and price > #{min}--> <!-- ]]>--> </select>
直接运行测试结果和 <![CDATA[ ]]>字符一样
我的分享到这里就结束了,感兴趣的老铁点赞加关注,后续我会继续与老铁们分享
一波三连,拜托拜托