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;

    @Override
    public 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 {

    @Autowired
    EmpMapper empMapper;// 如果配置错误那么会显示无法注入
    @Test
    void 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.phone
        from t_order o
                 left join t_customer c on o.customer_id =c.id
        where 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 c
                 left join t_order o on c.id =o.customer_id
        where 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_order
    where 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_customer
        where 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=true

mybatis.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获取Emp
    List<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_emp
        where
        <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获取Emp
    List<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 {
        @Bean
        PageInterceptor 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 {
        @Autowired
        EmpMapper empMapper;
        @Test
        public 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属性对应的就是分页查询的结果,其他属性对应别的参数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法设计与分析】实验1:字符串匹配问题的算法设计与求解

目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 给定一个文本&#xff0c;在该文本中查找并定位任意给定字符串。 1、深刻理解并掌握蛮力法的设计思想&#xff1b; 2、提高应用…

10.6.1 文本文件读、写和追加

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 文本文件的读写通常的做法是建立一个与文件关联的filestream&#xff0c;然后使用StreamReader读取或者StreamWriter写入。 为了详…

DevEco Studio 4.1中如何创建OpenHarmony的Native C++ (NAPI)程序

目录 引言 操作步骤 结语 引言 OpenHarmony的开发工具变化很快&#xff0c;有的时候你安装以前的教程进行操作时会发现界面和操作方式都变了&#xff0c;进行不下去了。比如要在OpenHarmony中通过NAPI调用C程序&#xff0c;很多博文&#xff08;如NAPI篇【1】——如何创建含…

达梦拷贝DM_HOME的复制安装

近期一个项目需求&#xff0c;需要在没有安装包的情况下&#xff0c;将达梦数据库安装到虚机上&#xff08;生产机上安装了达梦&#xff09;&#xff0c;故采用直接打包生产机DM_HOME的方式拷贝至虚机&#xff0c;再依次执行达梦的部分指令完成安装。以下为验证的步骤&#xff…

【MySQL】初始MySQL、库与表的操作

目录 基本使用 使用案例 SQL分类 存储引擎 库的操作 字符集和校验规则 查看系统默认字符集和校验规则 查看数据库支持的字符集 查看数据库支持的字符集校验规则 指定编码常见数据库 校验规则对数据库的影响 操纵数据库 库的备份与恢复 表的操作 创建表 查看表 …

AI大模型开发原理篇-2:语言模型雏形之词袋模型

基本概念 词袋模型&#xff08;Bag of Words&#xff0c;简称 BOW&#xff09;是自然语言处理和信息检索等领域中一种简单而常用的文本表示方法&#xff0c;它将文本看作是一组单词的集合&#xff0c;并忽略文本中的语法、词序等信息&#xff0c;仅关注每个词的出现频率。 文本…

“爱”之浅谈(一)

《九重紫》里 陈嘉有了爱情 从粗糙的一介武夫和赌徒&#xff0c;变得温柔细致 万皇后伤于爱情 从温柔的眼里有爱有光的小姑娘&#xff0c;变成狠毒的残害忠良的、意图谋反的、卷动举国风云的操盘手 “爱让怯懦者勇敢&#xff0c;让高傲者低头” “爱是软肋&#xff0c;也是…

图漾相机搭配VisionPro使用简易教程

文章目录 1.下载并安装VisionPro软件2.下载PercipioCameraForVisionPro软件包3.软件部署4.测试流程4.1 遍历VisionPro SDK支持的参数4.2 设置示例4.2.1_cameraSingle.SetTriggerMode4.2.2 _cameraSingle.SetRegistration4.2.3_cameraSingle.SetInt4.2.4 _cameraSingle.GetInt4.…

Versal - 基础3(AXI NoC 专题+仿真+QoS)

目录 1. 简介 2. 示例 2.1 示例说明 2.2 创建项目 2.2.1 平台信息 2.2.2 AXI NoC Automation 2.2.3 创建时钟和复位 2.3 配置 NoC 2.4 配置 AXI Traffic 2.5 配置 Memory Size 2.6 Validate BD 2.7 添加观察信号 2.8 运行仿真 2.9 查看结果 2.9.1 整体波形 2.9…

iperf 测 TCP 和 UDP 网络吞吐量

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

ResNeSt: Split-Attention Networks论文学习笔记

这张图展示了一个名为“Split-Attention”的神经网络结构&#xff0c;该结构在一个基数组&#xff08;cardinal group&#xff09;内进行操作。基数组通常指的是在神经网络中处理的一组特征或通道。图中展示了如何通过一系列操作来实现对输入特征的注意力机制。 以下是图中各部…

自动驾驶---苏箐对智驾产品的思考

1 前言 对于更高级别的自动驾驶&#xff0c;很多人都有不同的思考&#xff0c;方案也好&#xff0c;产品也罢。最近在圈内一位知名的自动驾驶专家苏箐发表了他自己对于自动驾驶未来的思考。 苏箐是地平线的副总裁兼首席架构师&#xff0c;同时也是高阶智能驾驶解决方案SuperDri…

【C++】内联函数inline、关键字auto与新式for

内联函数 内联函数背景 我们在使用C语言中我们都学过函数&#xff0c;我们知道函数在调用的过程中需要开辟栈帧。如果我们需要频繁的调用一个函数&#xff0c;假设我们调用10次Add()函数&#xff0c;那我们就需要建立10次栈帧。我们都知道在栈帧中要做很多事情&#xff0c;例如…

Day24-【13003】短文,数据结构与算法开篇,什么是数据元素?数据结构有哪些类型?什么是抽象类型?

文章目录 13003数据结构与算法全书框架考试题型的分值分布如何&#xff1f; 本次内容概述绪论第一节概览什么是数据、数据元素&#xff0c;数据项&#xff0c;数据项的值&#xff1f;什么是数据结构&#xff1f;分哪两种集合形式&#xff08;逻辑和存储&#xff09;&#xff1f…

论文阅读(十六):利用线性链条件随机场模型检测阵列比较基因组杂交数据的拷贝数变异

1.论文链接&#xff1a;Detection of Copy Number Variations from Array Comparative Genomic Hybridization Data Using Linear-chain Conditional Random Field Models 摘要&#xff1a; 拷贝数变异&#xff08;CNV&#xff09;约占人类基因组的12%。除了CNVs在癌症发展中的…

深入理解若依RuoYi-Vue数据字典设计与实现

深入理解若依数据字典设计与实现 一、Vue2版本主要文件目录 组件目录src/components&#xff1a;数据字典组件、字典标签组件 工具目录src/utils&#xff1a;字典工具类 store目录src/store&#xff1a;字典数据 main.js&#xff1a;字典数据初始化 页面使用字典例子&#xf…

思维练习题

目录 第一章 假设法1.题目1. 如何问问题2. 他们的职业是分别什么3. 谁做对了4. 鞋子的颜色 2.答案 空闲时间写一些思维题来锻炼下思维逻辑&#xff08;题目均收集自网上&#xff0c;分析推理为自己所写&#xff09;。 第一章 假设法 一个真实的假设往往可以让事实呈现眼前&…

亲测有效!解决PyCharm下PyEMD安装报错 ModuleNotFoundError: No module named ‘PyEMD‘

解决PyCharm下PyEMD安装报错 PyEMD安装报错解决方案 PyEMD安装报错 PyCharm下通过右键自动安装PyEMD后运行报错ModuleNotFoundError: No module named ‘PyEMD’ 解决方案 通过PyCharm IDE python package搜索EMD-signal&#xff0c;选择版本后点击“install”执行安装

DVC - 数据版本和机器学习实验的命令行工具和 VS Code 扩展

文章目录 一、关于 DVC二、快速启动三、DVC的工作原理四、VS代码扩展五、安装Snapcraft&#xff08;Linux&#xff09;Chocolatey (Windows)Brew (mac OS)Anaconda (Any platform)PyPI&#xff08;Python&#xff09;Package (Platform-specific)Ubuntu / Debian (deb)Fedora /…

实现前端当中的页面过渡动画

使用 HTML、CSS 和 JavaScript 实现页面过渡动画 在现代网页设计中&#xff0c;用户体验是至关重要的。而页面切换时的平滑过渡效果&#xff0c;不仅能让界面更加美观&#xff0c;也能增强用户的互动体验。 引言 作为一名热爱前端开发的程序员&#xff0c;我一直在寻找能提…