SSM-MyBatis-总结

文章目录

    • 一、Hello MyBatis
      • 1.1 流程
      • 1.2 总结
    • 二、Crud 的一些注意点
    • 三、参数传递
      • 3.1 #{ } VS ${ }
      • 3.2 单、复参数传递
        • (1)单参数
        • (2)多参数 -- @Param
        • (3)总结
    • 四、查询结果返回--结果封装
        • 4.1 @ResultType 一般返回
        • 4.2 @ResultMap 使用自定义映射规则
        • 4.3 总结,最佳实践
    • 五、自定义结果集
      • ▽ 关联关系
      • 5.1 关联查询
        • (1) 一对一 ^【association】^
        • (2) 一对多^【collection】^
      • 5.2 分布查询
        • (1)原生分布查询
        • (2)MyBatis自动分布查询
        • (3)延迟查询^(延迟加载)^
    • 六、动态SQL语句
      • 6.1 < if >标签
      • 6.2 < where >标签
      • 6.3 < set >标签
      • 6.4 < trim >标签^(自定义截串规则)^
        • (1)内部属性
        • (2)对where标签的替换:
        • (3)对于set标签的替换
      • 6.5 choose--when--otherwise 标签
      • 6.6 < foreach > 标签
        • (1)内部属性
        • (2)基本使用:遍历插入/查询
        • (3)基本使用:遍历更新/删除
        • ▽ 是否使用多sql一起发送
      • ▽ 可重复字段
      • 6.7 总结
    • ▽ XML文件的转义字符
    • 七、缓存机制
      • 6.1 什么是缓存机制
      • 6.2 MyBatis的缓存机制
    • 八、插件机制
      • 8.1 插件拦截
      • 8.2 应用:PageHelper 分页插件
        • (1)基本使用
        • (2)进阶使用^(前后端请求响应交互)^

一、Hello MyBatis

1.1 流程

  1. 导入MyBatis、配置数据库

  2. 创建Bean组件

@Data
public class Employee {Integer id;String name;Integer age;Double salary;@Overridepublic String toString() {return "Employee{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", salary=" + salary +'}';}
}
  1. 创建Dao层接口(在MyBatis中文件目录写成mapper),并标识@Mapper
@Mapper
public interface EmpMapper {Employee getEmpById(Integer id);}
  1. 通过IDEA的插件创建resources目录中的mapper.xml,xml文件中的select、update…方法会被MyBatis自动通过代理对象生成对应的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.syq.mybatis02.dao.EmpMapper"><select id="getEmpById" resultType="com.syq.mybatis02.bean.Employee">select id, emp_name as name, age, emp_salary as salary from t_emp where id = #{id}</select>
</mapper>

注意:

  • 数据库查询的字段和bean对象的名字是否一样,如果不一样需要使用as 把查询到的数据库的字段名改掉
  • 注意xml文件中的方法和mapper接口的方法名、返回类型、(参数类型)是否一样,
  1. **在 [application.properties]中配置对应的mapper.xml **
mybatis.mapper-locations=classpath:mapper/**.xml
  1. 实际使用
@SpringBootTest
class MyBatis02ApplicationTests {@AutowiredEmpMapper empMapper;// 如果配置错误那么会显示无法注入@Testvoid contextLoads() {Employee empById = empMapper.getEmpById(1);System.out.println("emp:"+empById);}}

1.2 总结

  • MyBatis是个半自动的Dao工具,配置比较复杂但后续使用还算方便,一定要认真检查配置
  • MyBatis的底层是接口的代理实现,实际使用的也是代理出来的对象和方法,当配置有误时–>代理没有正常创建,就无法通过接口的多态性注入到容器中

二、Crud 的一些注意点

  1. 打开sql日志

    Mybatis默认在运行时,会根据xml文件中的sql生成sql,如果想要看自动生成的sql是什么样的可以开启sql日志,会在控制台中显示

    application.properties中:

    mybatis.mapper-locations=classpath:mapper/**.xml
    
  2. 获取数据库自增字段信息(自增信息回填)

    对于自增的数据库属性,比如传入一个Employee对象后、把数据库中自动生成的值传入原Employee对象的对应属性

    • useGeneratedKeys 使用生成的键 ture/false
    • keyProperty 键属性 对应属性

    mapper.xml中:

    <insert id="addEmp" parameterType="com.syq.mybatis02.bean.Employee" useGeneratedKeys="true" keyProperty="id"><!-- 这里 -->insert into t_emp(emp_name, age, emp_salary) values (#{name}, #{age}, #{salary})
    </insert>
    
  3. **查询所有或者查询多个 **

    在JDBC中需要把Dao方法返回类型设置为List,但是在MyBatis中的,mapper.xml直接使用Bean接收就行了,会自动封装成List

    @Mapper
    public interface EmpMapper {List<Employee> getAllEmp();
    }
    
    <select id="getAllEmp" resultType="com.syq.mybatis02.bean.Employee">select id, emp_name as name, age, emp_salary as salary from t_emp
    </select>
    
  4. 开启驼峰命名与_命名自动转换

    sql中的组合词以_分割,java中使用驼峰,开启后自动转换

    mybatis.configuration.map-underscore-to-camel-case=true
    

三、参数传递

sql语句需要一定灵活性,所以sql一些参数使用#{ }或者${ }传递

3.1 #{ } VS ${ }

他们都可以用于参数传递,但是仍有区别

  1. #{ }

    本质上就是预编译,将空位留给参数输入

    • 不会有sql注入问题
    • 只能传递属性的具体值–>比如age=18
  2. ${ }

    本质上是字符串拼接,直接把参数放到sql中

    • 有sql注入问题

      • 可以通过工具类先判断是否有sql注入风险,然后使用if限定
    • 除了值传递的功能以外,还可以传递类型–>比如指定具体的表名、字段名

3.2 单、复参数传递

(1)单参数

例如:

  1. 根据List< Integer >数组,通过第2个id查询

    Employee getEmpByIds(List<Integer> ids);
    
    <select id="getEmpByIds" resultType="com.syq.mybatis02.bean.Employee">select id, emp_name as name, age, emp_salary as salary from t_emp where id in=#{ids{1}}<!-- /索引从0开始 /只有一个容器时ids可以随便写比如abcd{1} -->
    </select>
    
  2. 根据对象查询

    Employee getEmpByEmp(Employee e);
    
    <select id="getEmpByEmp" resultType="com.syq.mybatis02.bean.Employee">select id, emp_name as name, age, emp_salary as salary from t_emp where id = #{id} <!-- 不用写e.id,如果写了相当于:有一个e的属性,e里面还有一个id属性 -->
    </select>
    

    此时,在mapper.xml配置中不一定要使用对应的形参名,因为只有一个参数,MyBatis自动会给匹配上

    但是,如果使用**@Param(“e”) 精确指定了参数名为e,则必须使用 e.属性** 来调用

  3. 根据Map内容查询

    Employee geEmpByMap(Map<String,Integer> map);
    
    <select id="geEmpByMap" resultType="com.syq.mybatis02.bean.Employee">select id, emp_name as name, age, emp_salary as salary from t_emp where id = #{id}
    </select>
    
(2)多参数 – @Param
List<Employee> getEmpAaa(@Param("id")Integer id,@Param("name") List<String> names,@Param("e") Employee employee
);
<select id="getEmpAaa" resultType="com.syq.mybatis02.bean.Employee">select id, emp_name as name, age, emp_salary as salary from t_emp where id = #{id} or emp_name = #{name} or emp_salary = #{e.salary}
</select>
  • 多参数时必须在mapper接口使用@Param指定参数名,xml中sql引入参数时也必须使用对应的参数名
(3)总结
  1. 最佳实践:

无论是一个参数还是多个参数,都使用@Param 标识

  1. 区别:
传参形式示例取值方式
单个参数 - 普通类型getEmploy(Long id)#{变量名}
单个参数 - List类型getEmploy(List id)#{变量名[0]}
单个参数 - 对象类型addEmploy(Employ e)#{对象中属性名}
单个参数 - Map类型addEmploy(Map<String,Object> m)#{map中属性名}
多个参数 - 无@ParamgetEmploy(Long id,String name)#{变量名} //新版兼容
多个参数 - 有@ParamgetEmploy(@Param(“id”)Long id, @Param(“name”)String name)#{param指定的名}
扩展:getEmploy(@Param(“id”)Long id, @Param(“ext”)Map<String,Object> m, @Param(“ids”)List ids, @Param(“emp”)Employ e)#{id}、 #{ext.name}、#{ext.age}, #{ids[0]}、#{ids[1]}, #{e.email}、#{e.age}

四、查询结果返回–结果封装

4.1 @ResultType 一般返回

本质上:
使用MyBatis的默认映射规则,把查询的内容封装到指定类型中

注意点:

  1. 返回对象、基本数据类型时:@ResultType=“全类名”
    • 虽然对于java自带的一些类型可以简写,但是不推荐
  2. 返回Map、List.集合时:@ResultType=“全类名”
    • 有时对于返回Map<,>封装结果的方法,插件生成的@ResultType使用了Map的全类名,此时虽然也得到了Map集合,但是其中的内容(Employee等自定义对象)也都变成了Map集合,这样不符合业务逻辑无法使用get方法,不建议使用
4.2 @ResultMap 使用自定义映射规则

有时就算开启了驼峰转换,或者是其他情况,此时我们可以自定义映射的规则,确保代码正常运行

例:

  • mapper.java

    Employee getEmpByName(@Param("name") String name);
    
  • mapper.xml

    <!--    自定义映射规则--><resultMap id="EmployeeRM" type="com.syq.mybatis02.bean.Employee"><id property="id" column="id"/><result property="name" column="emp_name"/><result property="age" column="age"/><result property="salary" column="emp_salary"/></resultMap>
    <!--    使用该规则-->
    <select id="getEmpByName"  resultMap="EmployeeToResult">select id, emp_name , age, emp_salary  from t_emp where emp_name = #{name}
    </select>
    
    • id标签:主键
    • result标签:普通字段
4.3 总结,最佳实践

步骤:

  1. 开启驼峰命名转换
  2. 如果无法转换,使用@ResultMap

五、自定义结果集

▽ 关联关系

  1. 一对一:

    多表联查产生一对一关系,比如一个订单对应唯一的一个下单客户

    • 此时需要保存客户与订单的关系键到其中的一个表中
  2. 一对多:

    多表查询的是一对多的关系,比如一个客户的购物车中有多个订单

    • 此时把对应关系存到为多的那一方的表中
  3. 多对多:

    查询的对应关系不存在一方为一时,比如一个客户的对应商家有多个、一个商家又服务多个客户

    • 此时要新建一个中间表记录客户和商家的关系

5.1 关联查询

我们要获取具有关联性的数据,可以sql的表关联 (a join b on a.id=b.id),而要如何接收sql的查询结果,则是我们要考虑的

(1) 一对一 【association】

因为使用关联查询,我们在sql查询器中查询得到的是一排数据,为了将其中各个表的数据分开存储,我们在自定义映射规则中引入一种把部分属性封装到一个对象中的标签【association】

使用例:
Order 与Customer 两个javaBean有关联

<?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.syq.mybatis03.mappers.OrderMapper">
<!--    映射规则	--><resultMap id="OrderRM" type="com.syq.mybatis03.bean.Order"><id column="id" property="id"></id><result column="address" property="address"></result><result column="amount" property="amount"></result><association property="customer" javaType="com.syq.mybatis03.bean.Customer"><!-- 重点 --><id column="customer_id" property="id"></id><result column="customer_name" property="customerName"></result><result column="phone" property="phone"></result></association></resultMap><!--    sql代码	--><select id="getOrderByIdWithCustomer" resultMap="OrderRM">select o.*,c.id  customer_id,c.customer_name customer_name,c.phonefrom t_order oleft join t_customer c on o.customer_id =c.idwhere c.id=#{id};</select></mapper>
  • 我们发现在association 标签中除了property属性 指定封装属性,还要使用javaType属性 指定对象的类型
(2) 一对多【collection】

当面对一对多关系时,查询结果有时为多行,此时我们不仅要将部分数据封装,而且要对于多行进行处理,处理成一个List集合,我们在自定义映射规则中引入一种把部分属性封装到一个List<对象>中的标签【collection】

使用例:

<?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" >
<!--suppress ALL -->
<mapper namespace="com.syq.mybatis03.mappers.CustomerMapper">
<!--    映射规则--><resultMap id="CustomerRM" type="com.syq.mybatis03.bean.Customer"><id column="c_id" property="id"></id><result column="customer_name" property="customerName"></result><result column="phone" property="phone"></result><collection property="orders" ofType="com.syq.mybatis03.bean.Order"><id column="id" property="id"></id><result column="address" property="address"></result><result column="amount" property="amount"></result><result column="c_id" property="customerId"></result></collection></resultMap><!--    sql语句--><select id="getCustomerById" resultMap="CustomerRM">select c.id c_id,c.phone phone,c.customer_name customer_name,o.*from t_customer cleft join t_order o on c.id =o.customer_idwhere c.id=${id};</select>
</mapper>
  • 我们发现在collection 标签中除了property属性 指定封装属性,还要使用ofType属性 指定集合元素的类型association则是javaType

5.2 分布查询

关联查询适用于有关联关系的查询(本质上是对通过关联关系查询一次得到的容器进行分层封装),而还有一种“分布查询”的方式,除了关联关系对于没有关联关系的查询也能得到结果(本质上是对于头一次sql得不到的数据,进行再次查询,依次类推直到数据全部得到并将其封装完毕)

(1)原生分布查询

通过方法手动调用多次Dao方法,如何把结果封装并返回

(2)MyBatis自动分布查询

分布查询的本质是对于头一次sql得不到的数据,进行多次查询,也就是多个sql语句,同理我们在xml中配置多个< select > 标签并整合到resultMap 的 collection或者association的select中就能做到分布查询

基础sql:

<select id="getOrderByIdWithCustomer2" resultMap="OrderRM2">select *from t_orderwhere id = #{id};
</select>
  • 使用的是resultMap,不是resultType

resultMap:

<!--    分布查询,获取Order--><resultMap id="OrderRM2" type="com.syq.mybatis03.bean.Order"><id column="id" property="id"></id><result column="address" property="address"></result><result column="amount" property="amount"></result><collection property="customer"<!-- 重点 -->select="com.syq.mybatis03.mappers.OrderMapper.getCustomerByOrderId"<!-- 重点 -->column="{id=customer_id}"></collection></resultMap>
  • 这里使用的是collection标签处理一对多关系,同理association也可以
  • select=" "指定的最好是全类名
  • column=" “指定的是sql方法对应的参数,写成KeyV形式,有多个时:”{K=V,K=V,K=V}"

内层sql:

<select id="getCustomerByOrderId" resultType="com.syq.mybatis03.bean.Customer">select *from t_customerwhere id=#{id};
</select>
  • 这里使用的是resultType 而不是Map,以此类推:
    • 如果是Map属性:则表示仍要继续
    • 如果是Type属性:表示不用继续了,已经到结尾了

注意点:
要小心查询,避免出现无限重复的查询代码,引发栈溢出等问题
要规避的话可以:注意分布查询存在有resultType的select标签,注意每次使用resultMap所指向的封装规则

(3)延迟查询(延迟加载)

当使用的Dao方法会引发大量的分布查询时,我们可以通过延迟查询机制(类似于懒加载的延迟),只加载到方法所需要的数据的那一步,从而减少损耗

对应的两行配置

•mybatis.configuration.lazy-loading-enabled=true

•mybatis.configuration.aggressive-lazy-loading=false

mybatis.configuration.lazy-loading-enabled=truemybatis.configuration.aggressive-lazy-loading=false

六、动态SQL语句

先前我们学习MyBatis的查询,但是对于sql只能拼接处理,不能在sql语句的层次进行分支、条件……的判断,而MyBatis可以通过一系列标签来做到这种动态变化

6.1 < if >标签

和JavaSE中的if类似,但是判断条件是其中的 test属性

以根据id 或者age 获取Emp为例子

  1. .java文件:
@Mapper
public interface EmpMapper {// 根据id或者age获取EmpList<Emp> getEmps1(@Param("id") Integer id,@Param("age") Integer age);
}
  1. .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.syq.mybatis03.mappers.EmpMapper"><select id="getEmps1" resultType="com.syq.mybatis03.bean.Emp">select * from t_empwhere<if test="id!=null"><!-- 这里,判断不为空 -->id=#{id}</if><if test="age!=null"><!-- 这里,判断不为空 -->and age=#{age};</if></select>
</mapper>
  • 但是仅仅如此解决满足需求如果只传入一个age 属性,那么程序会出错(原因是拼接的是 and age=#{age},其中and 违反了sql的语法规范)

6.2 < where >标签

对于6.1中的实现方式,如果只传入一个age 属性,那么程序会出错
于是,通过where 标签,MyBatis 会将where标签中的and、or 等语法错误纠正,这样就能满足需求了

  1. .java文件(和上面一样):
@Mapper
public interface EmpMapper {// 根据id或者age获取EmpList<Emp> getEmps2(@Param("id") Integer id,@Param("age") Integer age);
}
  1. .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.syq.mybatis03.mappers.EmpMapper"><select id="getEmps1" resultType="com.syq.mybatis03.bean.Emp">select * from t_emp<where><!-- 这里,设置了where标签 --><if test="id!=null"><!-- 这里,判断不为空 -->id=#{id}</if><if test="age!=null"><!-- 这里,判断不为空 -->and age=#{age};</if></where></select>
</mapper>

6.3 < set >标签

类似于where标签,但是是针对更新数据时使用

对于sql中的where我们有了处理的方法,但是举个例子:

update t_emp set <if test="salary!=null">emp_salary=${salary} ,</if><if test="id!=null">age=${age} where id=${id};</if>

对于这种情况,如果我们只用salary查询,那么会报错,因为结尾存在一个","号,此时,我们就要使用< set >标签

  1. .java文件:
void setEmp1(Emp emp);
  1. .xml文件:
<update id="setEmp1" parameterType="com.syq.mybatis03.bean.Emp">update t_emp<set><if test="empSalary != null">emp_salary = #{empSalary},</if><if test="age != null">age = #{age},</if><if test="empName != null">emp_name = #{empName}</if></set>where id = #{id};
</update>
  • **注意:**虽然不知道什么原因,只有一个对象参数使用@Param后居然无法调用其属性,自己写代码时要小心,或者之后搞明白原因

6.4 < trim >标签(自定义截串规则)

trim标签能替代where或者set标签,本质是:where和set都是对于if 中语句的特定前后缀进行判断修改,而trim 标签则是将修改的内容交给程序员(比如and为前缀,或是","为后缀)

(1)内部属性
属性用途
prefix设置前缀
suffix设置后缀
prefixOverrides前缀覆盖
suffixOverrides后缀覆盖
  • **注意:**这里的设置前后缀,只有当trim 中存在内容时才会推荐;如果没有内容,就没有前后缀
(2)对where标签的替换:

whre标签的本质是对于其内以and、or开头的字符串用 空 覆盖and、or

  1. .java文件:
// 根据id或者age获取Emp--2
List<Emp> getEmps2(@Param("id") Integer id,@Param("age") Integer age);
  1. .xml文件:
<select id="getEmps2" resultType="com.syq.mybatis03.bean.Emp">select * from t_emp<trim prefix="where" prefixOverrides="and"><!-- 如果标签中包含的字符串以and开头,则用空的内容覆盖掉and --><if test="id!=null">id=#{id}</if><if test="age!=null">and age=#{age};</if></trim>
</select>
  • **原理:**如果标签中包含的字符串以and开头,则用空的内容覆盖掉and
(3)对于set标签的替换

set标签的本质是对以“,”结尾的字符串用 空 替换

  1. .java文件:
// 更新Emp--2
void setEmp2(Emp emp);
  1. .xml文件:
<update id="setEmp2">update t_emp<trim prefix="set" suffixOverrides=","><!-- 如果标签中包含的字符串以“,”结尾,则用 空 的内容覆盖掉 --><if test="empSalary != null">emp_salary = #{empSalary},</if><if test="age != null">age = #{age},</if><if test="empName != null">emp_name = #{empName}</if></trim>where id = #{id};
</update>
  • **原理:**如果标签中包含的字符串以“,”结尾,则用 空 的内容覆盖掉

6.5 choose–when–otherwise 标签

就是javaSE中的switch–case–default 的翻版

仍然以根据id或者age获取Emp为例

  1. .java文件
// 根据id或者age获取Emp--3--这个方法只能使用一个参数
List<Emp> getEmps3(@Param("id") Integer id,@Param("age") Integer age);
  1. .xml文件
<select id="getEmps3" resultType="com.syq.mybatis03.bean.Emp">select * from t_emp<where><choose><when test="id!=null">id=#{id}</when><when test="age!=null">age=#{age}</when><otherwise>id=2</otherwise></choose></where>
</select>

6.6 < foreach > 标签

前面我们学了这么多但是当对于集合,我们无法确定集合中有多少参数,此时不妨使用foreach 来遍历集合,并拼接到sql语句中

(1)内部属性
属性作用
collection确定遍历的集合的名字
item指定集合的元素对应的实例名
separator指定每次遍历的分隔符
open整个遍历开始前的前缀
(2)基本使用:遍历插入/查询

其实也可以在查询时使用,不过这里直接以插入为代表

  1. java文件:
// 添加一堆Emp
void addEmp1(List<Emp> emps);
  1. xml文件:
<insert id="addEmp1">insert into t_emp(emp_name, age, emp_salary)values<foreach collection="emps" item="emp" separator=",">(#{emp.empName},#{emp.age},#{emp.empSalary})</foreach>
</insert>
(3)基本使用:遍历更新/删除

更新与删除在sql层面每一次都需要一个新的sql语句(以“;”结尾算是一条语句),所以需要用“;”号分隔遍历,而默认情况下MyBatis不支持一次Dao带有多条sql语句需要在配置数据库的代码后添加/mybatis-example?allowMultiQueries=true

spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-example?allowMultiQueries=true#在这里
spring.datasource.username=root
spring.datasource.password=syq8257507
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

以遍历更新为例:

  1. .java文件:
// 更新一堆Emp
void setEmp3(List<Emp> emps);
  1. .xml文件:
<update id="setEmp3">update t_emp<foreach collection="emps" item="emp" separator=";"><set><if test="emp.empSalary != null">emp_salary = #{emp.empSalary},</if><if test="emp.age != null">age = #{emp.age},</if><if test="emp.empName != null">emp_name = #{emp.empName}</if></set></foreach>
</update>

注意:

  • 如果不使用MyBatis遍历,而是在java代码中遍历,那么后者的效率远不如前者,因为后者的交互次数多,而前者只有一次
▽ 是否使用多sql一起发送

前面我们在遍历更新时使用了这种功能,虽然能大幅度提高效率,但是在一些情况下这种功能并不一定好

  • 当我们需要对每个sql做好事务回滚:如果使用这种功能,那么一旦后面有错,那么前面的数据也一块回滚了
  • 在分布式框架中不能使用:具体原因未知,等后续学到

▽ 可重复字段

当有些内容过长而且经常出现,此时可以用可重复字段代替

  1. 创建复用字段:
<sql id="user_name">id,emp_name empName,age
</sql>
  1. 使用:
    <select id="getEmp" resultType="com.syq.mybatis03.bean.Emp">select <include refid="user_name"></include><!-- 这里使用 -->from t_emp<where><choose><when test="id!=null">id=#{id}</when><when test="age!=null">age=#{age}</when><otherwise>id=2</otherwise></choose></where></select>

6.7 总结

动态SQL语句的实现原理是MyBatis的自动拼串机制,我们所谓的sql动态化其本质就是对该机制的应用。又由于MyBatis在xml文件中,所以我们使用了一系列似曾相识的标签来规范这种操作

▽ XML文件的转义字符

我们的MyBatis使用xml配置,所以一些字符要以xml的规则,写成转义字符

原始字符转义字符
&&
<<
>>
""
'

七、缓存机制

6.1 什么是缓存机制

字面意思,暂缓存储:通过N级的缓存,调节运算速度和存储空间,从而改善处理装置和存储装置之间交互效率

**例:**计算机的cpu和其硬盘

6.2 MyBatis的缓存机制

MyBatis作为服务器与数据源的交互处,为了效率考虑也建立了缓存的机制

  • 了解即可,以后有专门的工具

MyBatis 拥有二级缓存机制:

  • **一级缓存:**默认开启;

    • 事务级别:当前事务共享
  • **二级缓存:**手动配置开启

    • 开启方式:在mapper.xml中标识< cache/ >标签
    • 事务级别:所有事务共享
  • 缓存中有就不用查数据库;

八、插件机制

为了应对不同的情况,MyBatis 也能组载插件

  • 底层原理不用细究,过于复杂,大部分时间会用别人写的插件即可

8.1 插件拦截

MyBatis 底层使用 拦截器机制提供插件功能,方便用户在SQL执行前后进行拦截增强。

  • 拦截器:Interceptor

  • 拦截器可以拦截 四大对象 的执行

    • ParameterHandler:处理SQL的参数对象
    • ResultSetHandler:处理SQL的返回结果集
    • StatementHandler:数据库的处理对象,用于执行SQL语句
    • Executor:MyBatis的执行器,用于执行增删改查操作

8.2 应用:PageHelper 分页插件

虽然我们可以在sql语句中配置分页操作,但是实际业务比较麻烦,可以通过分页插件较为简单并统一地给前端发数据,在减少后端代码量的同时便于前端接收并使用分页数据

(1)基本使用
  1. maven配置:

    <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>最新版本号</version>
    </dependency>
    
  2. 配置类配置:

    package com.syq.mybatis03.config;import com.github.pagehelper.PageInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;import java.util.Properties;@Configuration
    public class MyBatisConfig {@BeanPageInterceptor myBatisConfigBean(){// 创建分页插件PageInterceptor pageInterceptor = new PageInterceptor();// 设置,以分页合理化为例Properties properties = new Properties();// 创建设置项properties.setProperty("reasonable","true");// 修改设置项pageInterceptor.setProperties(properties);// 添加设置项// 完成插件配置return pageInterceptor;}
    }
    
    • **什么是分页合理化:**超过最大按最大页数算,少于1按1算
  3. 实际使用:

    @SpringBootTest
    public class PageTest {@AutowiredEmpMapper empMapper;@Testpublic void test1() {PageHelper.startPage(1,3);// 在每次需要用到分页时使用:(当前页数,一页记录数)for (Emp emp : empMapper.getEmpAll()) {System.out.println(emp);}}
    }
    
  4. 注意:

    • 调用PageHelper.startPage( , ) 方法,只能对其后第一个方法调用有效,原理是后一个方法获取的是插件产生的共享数据,当方法获取完毕,该数据自动销毁
(2)进阶使用(前后端请求响应交互)

前面我们只是在后端进行了分页,但是对于真正开发来说,前端会需要更详细的信息,比如:总页数、当前是第几页、页面内容的大小。

此时我们使用PageInfo< Object > Info 对象,为前端获取这些信息

例:

@Test
public void test2() {PageHelper.startPage(1,3);List<Emp> empAll = empMapper.getEmpAll();System.out.println("--------------------************************");PageInfo<Emp> empPageInfo = new PageInfo<>(empAll);// 获取信息System.out.println("每页显示的条数:"+empPageInfo.getPageSize());// 每页显示的条数System.out.println("总页数:"+empPageInfo.getPages());// 总页数System.out.println("总记录数:"+empPageInfo.getTotal());// 总记录数System.out.println("查询结果:"+empPageInfo.getList());// 查询结果}

效果:

在这里插入图片描述

  • **注:**实际使用时会放在Controller方法的返回值里(作为JSON串发给前端),info中的list属性对应的就是分页查询的结果,其他属性对应别的参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9786.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全面解析文件上传下载删除漏洞:风险与应对

在数字化转型的时代&#xff0c;文件上传、下载与删除功能已经成为各类应用程序的标准配置&#xff0c;从日常办公使用的协同平台&#xff0c;到云端存储服务&#xff0c;再到社交网络应用&#xff0c;这些功能在给用户带来便捷体验、显著提升工作效率的同时&#xff0c;也隐藏…

GSI快速收录服务:让你的网站内容“上架”谷歌

辛苦制作的内容无法被谷歌抓取和展示&#xff0c;导致访客无法找到你的网站&#xff0c;这是会让人丧失信心的事情。GSI快速收录服务就是为了解决这种问题而存在的。无论是新上线的页面&#xff0c;还是长期未被收录的内容&#xff0c;通过我们的技术支持&#xff0c;都能迅速被…

JavaScript

书写位置 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>/*C…

Go的内存逃逸

Go的内存逃逸 内存逃逸是 Go 语言中一个重要的概念&#xff0c;指的是本应分配在栈上的变量被分配到了堆上。栈上的变量在函数结束后会自动回收&#xff0c;而堆上的变量需要通过垃圾回收&#xff08;GC&#xff09;来管理&#xff0c;因此内存逃逸会增加 GC 的压力&#xff0…

python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。 按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位异或运算&#xff1a; 两个等长度二进制数上下对齐&#xff0c;相…

图论——最小生成树的扩展应用

最小生成树相关原理 acwing1146.新的开始 假设存在一个“超级发电站” 在每一个矿井修发电站相当于从这个“超级发电站”到各个矿井连一条长度为 v [ i ] v[i] v[i]的边。 这样一来这就是一个最短路的模板题。 #include <iostream> #include <cstring> using na…

供应链系统设计-供应链中台系统设计(十)- 清结算中心概念片篇

综述 我们之前在供应链系统设计-中台系统设计系列&#xff08;五&#xff09;- 供应链中台实践概述文章中针对中台到底是什么进行了描述&#xff0c;对于中台的范围也进行划分&#xff0c;如下图所示&#xff1a; 关于商品中心&#xff0c;我们之前用4篇文章介绍了什么是商品中…

Git图形化工具【lazygit】

简要介绍一下偶然发现的Git图形化工具——「lazygit」 概述 Lazygit 是一个用 Go 语言编写的 Git 命令行界面&#xff08;TUI&#xff09;工具&#xff0c;它让 Git 操作变得更加直观和高效。 Github地址&#xff1a;https://github.com/jesseduffield/lazygit 主要特点 主要…

为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1

为大模型提供webui界面的利器&#xff1a;Open WebUI Open WebUI的官网&#xff1a;&#x1f3e1; Home | Open WebUI 开源代码&#xff1a;WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&am…

全程Kali linux---CTFshow misc入门(14-24)

第十四题&#xff1a; dd命令&#xff1a;dd是一个用于复制和转换数据的命令&#xff0c;它可以对文件、设备等进行操作&#xff0c;在数据备份、转换格式等场景经常使用。 ifmisc14.jpg&#xff1a;if表示 “input file”&#xff08;输入文件&#xff09;&#xff0c;这里指…

网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开。

一、前言 我从24年11月份开始学习网络爬虫应用开发&#xff0c;经过2个来月的努力&#xff0c;于1月下旬完成了开发一款网络爬虫软件的学习目标。这里对本次学习及应用开发进行一下回顾总结。 前几天我已经发了一篇日志&#xff08;网络爬虫学习&#xff1a;应用selenium从搜…

C语言连接Mysql

目录 C语言连接Mysql下载 mysql 开发库 方法介绍mysql_init()mysql_real_connect()mysql_query()mysql_store_result()mysql_num_fields()mysql_fetch_fields()mysql_fetch_row()mysql_free_result()mysql_close() 完整代码 C语言连接Mysql 下载 mysql 开发库 方法一&#xf…

前端-Rollup

Rollup 是一个用于 JavaScript 的模块打包工具&#xff0c;它将小的代码片段编译成更大、更复杂的代码&#xff0c;例如库或应用程序。它使用 JavaScript 的 ES6 版本中包含的新标准化代码模块格式&#xff0c;而不是以前的 CommonJS 和 AMD 等特殊解决方案。ES 模块允许你自由…

Ubuntu20.04 磁盘空间扩展教程

Ubuntu20.04 磁盘空间扩展教程_ubuntu20 gpart扩容-CSDN博客文章浏览阅读2w次&#xff0c;点赞38次&#xff0c;收藏119次。执行命令查看系统容量相关的数据&#xff1a;df -h当前容量为20G&#xff0c;已用18G&#xff08;96%&#xff09;&#xff0c;可用844M&#xff0c;可用…

使用Ollama本地部署DeepSeek R1

前言 DeepSeek是一款开源的智能搜索引擎&#xff0c;能够通过深度学习技术提高搜索的智能化水平。如果你正在寻找一种方式来将DeepSeek部署在本地环境中&#xff0c;Ollama是一个非常方便的工具&#xff0c;它允许你在本地快速部署并管理各种基于AI的模型。 在本篇博客中&…

数据结构选讲 (更新中)

参考 smWCDay7 数据结构选讲2 by yyc 。 可能会补充的&#xff1a; AT_cf17_final_j TreeMST 的 F2 Boruvka算法 目录 AT_cf17_final_j Tree MSTP5280 [ZJOI2019] 线段树 AT_cf17_final_j Tree MST link 题意 给定一棵 n n n 个点的树&#xff0c;点有点权 w i w_i wi​&am…

Redis学习之哨兵二

一、API 1.sentinel masters:展示被监控的主节点状态及相关的统计信息 2.sentinel master <master name>:展示指定的主节点的状态以及相关的统计信息 3.sentinel slaves <master name>:展示指定主节点的从节点状态以及相关的统计信息 4.sentinel sentinels <mas…

iperf 测 TCP 和 UDP 网络吞吐量

注&#xff1a;本文为 “iperf 测网络吞吐量” 相关文章合辑。 未整理去重。 使用 iperf3 监测网络吞吐量 Tom 王 2019-12-21 22:23:52 一 iperf3 介绍 (1.1) iperf3 是一个网络带宽测试工具&#xff0c;iperf3 可以擦拭 TCP 和 UDP 带宽质量。iperf3 可以测量最大 TCP 带宽…

Kafka 副本机制(包含AR、ISR、OSR、HW 和 LEO 介绍)

文章目录 Kafka 副本机制&#xff08;包含AR、ISR、OSR、HW 和 LEO 介绍&#xff09;1. 副本的基本概念2. 副本同步和一致性2.1 AR&#xff08;Assigned Replicas&#xff09;2.2 ISR&#xff08;In-Sync Replicas&#xff09;2.3 OSR&#xff08;Out-of-Sync Replicas&#xf…

java求职学习day18

常用的设计原则和设计模式 1 常用的设计原则&#xff08;记住&#xff09; 1.1 软件开发的流程 需求分析文档、概要设计文档、详细设计文档、编码和测试、安装和调试、维护和升级 1.2 常用的设计原则 &#xff08;1&#xff09;开闭原则&#xff08;Open Close Principle…