mybatis说明

news2024/11/26 5:24:31

目录

1.说明

2.配置文件

3.映射器

4.select标签

5.insert标签

6.update标签

7.delete标签

8.resultMap的特别说明

9.注解

10.关联(级联)查询

11.动态sql

12.mybatis分页

13缓存


1.说明

MyBatis 是一个开源、轻量级的数据持久化框架,是 JDBC 和 Hibernate 的替代方案。MyBatis 内部封装了 JDBC,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,开发者只需要关注 SQL 语句本身。

MyBatis 支持定制化 SQL、存储过程以及高级映射,可以在实体类和 SQL 语句之间建立映射关系,是一种半自动化的 ORM 实现。其封装性低于 Hibernate,但性能优秀、小巧、简单易学、应用广泛。

优点:

  • MyBatis 是免费且开源的。
  • 与 JDBC 相比,减少了 50% 以上的代码量。
  • MyBatis 是最简单的持久化框架,小巧并且简单易学。
  • MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 中,和程序逻辑代码分离,降低耦合度,便于同一管理和优化,提高了代码的可重用性。
  • 提供 XML 标签,支持编写动态 SQL 语句。
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射。
  • 支持存储过程。MyBatis 以存储过程的形式封装 SQL,可以将业务逻辑保留在数据库之外,增强应用程序的可移植性、更易于部署和测试。

缺点:

  • 编写 SQL 语句工作量较大,对开发人员编写 SQL 语句的功底有一定要求。
  • SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

2.配置文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 配置 -->
    <properties /><!-- 属性 -->
    <settings /><!-- 设置 -->
    <typeAliases /><!-- 类型命名 -->
    <typeHandlers /><!-- 类型处理器 -->
    <objectFactory /><!-- 对象工厂 -->
    <plugins /><!-- 插件 -->
    <environments><!-- 配置环境 -->
        <environment><!-- 环境变量 -->
            <transactionManager /><!-- 事务管理器 -->
            <dataSource /><!-- 数据源 -->
        </environment>
    </environments>
    <databaseIdProvider /><!-- 数据库厂商标识 -->
    <mappers /><!-- 映射器 -->
</configuration>

mybatis-config.xml 文件中的元素节点是有一定顺序的,节点位置必须按以上位置排序,否则会编译错误。

现在使用spring boot集成mybatis一般不需要配置太多东西,大部分配置在spring boot的配置文件中。

3.映射器

  • 通过 XML 文件方式实现,比如我们在 mybatis-config.xml 文件中描述的 XML 文件,用来生成 mapper。
  • 通过注解的方式实现,使用 Configuration 对象注册 Mapper 接口。

(1)XML实现映射器

XML 定义映射器分为两个部分:接口和XML。

接口

package net.biancheng.mapper;
import java.util.List;
import net.biancheng.po.Website;
public interface WebsiteMapper {
    public List<Website> selectAllWebsite();
}

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="net.biancheng.mapper.WebsiteMapper">

    <!-- 查询所有网站信息 -->
    <select id="selectAllWebsite"
        resultType="net.biancheng.po.Website">
        select * from website
    </select>

</mapper>
  • namespace 用来定义命名空间,该命名空间和定义接口的全限定名一致。
  • <select> 元素表明这是一条查询语句,属性 id 用来标识这条 SQL。id要和接口中的方法名保持一致。

(2)注解方式

使用注解的方式实现映射器,只需要在接口中使用 Java 注解,注入 SQL 即可。

package net.biancheng.mapper;

import java.util.List;
import org.apache.ibatis.annotations.Select;
import net.biancheng.po.Website;

public interface WebsiteMapper2 {
    @Select(value = "select * from website")
    public List<Website> selectAllWebsite();
}

虽然这里注解的方式看起来比 XML 简单,但是现实中我们遇到的 SQL 会比该例子复杂得多。如果 SQL 语句中有多个表的关联、多个查询条件、级联、条件分支等,显然这条 SQL 就会复杂的多。因此不建议使用这种方式。

4.select标签

执行 SQL 语句时可以定义参数,参数可以是一个简单的参数类型,例如 int、float、String;也可以是一个复杂的参数类型,例如 JavaBean、Map 等。MyBatis 提供了强大的映射规则,执行 SQL 后,MyBatis 会将结果集自动映射到 JavaBean 中。

参数的传递使用#{参数名},相当于告诉 MyBatis 生成 PreparedStatement 参数。对于 JDBC,该参数会被标识为“?”。

常用标签属性

parameterType属性可以不写,mybatis能够推断出参数的类型。

传递参数的几种方式

(1)使用Map传递参数

public List<Website> selectWebsiteByMap(Map<String, String> params);
<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByMap" resultType="net.biancheng.po.Website" parameterType="map">
    SELECT id,NAME,url FROM website
    WHERE name LIKE CONCAT ('%',#{name},'%')
    AND url LIKE CONCAT ('%',#{url},'%')
</select>
Map<String,String> paramsMap = new HashMap<String,String>();
paramsMap.put("name","编程");
paramsMap.put("url","biancheng");
websiteMapper.selectWebsiteByMap(paramsMap);

使用 Map 传递参数虽然简单易用,但是由于这样设置参数需要键值对应,业务关联性不强,开发人员需要深入到程序中看代码,造成可读性下降。此方式不推荐。

(2)使用注解传递参数

public List<Website> selectWebsiteByAn(@Param("name") String name, @Param("url") String url);
<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByAn" resultType="net.biancheng.po.Website">
    SELECT id,NAME,url FROM website
    WHERE name LIKE CONCAT ('%',#{name},'%')
    AND url LIKE CONCAT ('%',#{url},'%')
</select>

当我们把参数传递给后台时,MyBatis 通过 @Param 提供的名称就会知道 #{name} 代表 name 参数,提高了参数可读性。但是如果这条 SQL 拥有 10 个参数的查询,就会造成可读性下降,增强了代码复杂性。

(3)使用JavaBean传递参数

public List<Website> selectWebsiteByAn(Website website);
<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByAn" resultType="net.biancheng.po.Website">
    SELECT id,NAME,url FROM website
    WHERE name LIKE CONCAT ('%',#{name},'%')
    AND url LIKE CONCAT ('%',#{url},'%')
</select>

(4)区别

使用 Map 传递参数会导致业务可读性的丧失,继而导致后续扩展和维护的困难,所以在实际应用中我们应该果断废弃该方式。

使用 @Param 注解传递参数会受到参数个数的影响。当 n≤3 时,它是最佳的传参方式,因为它更加直观;当 n>3 时,多个参数将给调用带来困难。

当参数个数大于 3 个时,建议使用 JavaBean 方式。

5.insert标签

 insert 标签用来定义插入语句,执行插入操作。当 MyBatis 执行完一条插入语句后,就会返回其影响数据库的行数。

(1)常用标签属性

注意:

insert 标签中没有 resultType及resultMap 属性,只有查询操作才需要对返回结果类型进行相应的指定。

传递参数的几种方式同select的一致。

(2)主键回填

我们知道,MySQL、SQL Server 等数据库表可以采用自动递增的字段作为其主键,oracle需要创建自增序列才能实现自增。当向这样的数据库表插入数据时,即使不指定自增主键的值,数据库也会根据自增规则自动生成主键并插入到表中。
以mysql为例,插入数据的时候指定主键自增,所以插入的项目不包含主键,一些特殊情况下,我们需要将这个刚刚生成的主键回填到请求对象(原本不包含主键信息的请求对象)中,供其他业务使用。此时,我们就可以通过在 insert 标签中添加  keyProperty 和 useGeneratedKeys 属性,来实现该功能。

<!--添加一个网站信息,成功后将主键值返回填给id(po的属性)-->
<insert id="addWebsite" parameterType="net.biancheng.po.Website" keyProperty="id" useGeneratedKeys="true">
    insert into Website (name,url) values(#{name},#{url})
</insert>

将useGeneratedKeys设置为true,代表将自增的值设置到keyProperty设置的属性值中,mysql支持多个主键,但是只有一个主键可以设置为自增。所以keyProperty只能设置一个值。

(3)自定义主键

如果在实际项目中,若数据库不支持主键自动递增(例如 Oracle),或者取消了主键自动递增的规则,我们可以使用 MyBatis 的 <selectKey> 标签自定义生成主键,具体配置代码如下。

<!-- 添加一个网站,#{name}为 net.biancheng.po.Website 的属性值 -->
<insert id="insertWebsite" parameterType="net.biancheng.po.Website">
    <!-- 先使用selectKey标签定义主键,然后再定义SQL语句 -->
    <selectKey keyProperty="id" resultType="Integer" order="BEFORE">
        select if(max(id) is null,1,max(id)+1) as newId from Website
    </selectKey>
    insert into Website (id,name,url) values(#{id},#{name},#{url})
</insert>



使用序列的方式

    <insert id="insertOrders" parameterType="com.example.demo.entity.Orders">
        INSERT INTO 语句
        <selectKey keyProperty="id" order="BEFORE" resultType="int">
            SELECT SEQ_ID.nextval from dual
        </selectKey>
    </insert>

<selectKey> 标签中属性说明如下:

  • keyProperty:用于指定主键值对应的 PO 类的属性。
  • order:该属性取值可以为 BEFORE 或 AFTER。BEFORE 表示先执行 <selectKey> 标签内的语句,再执行插入语句;AFTER 表示先执行插入语句再执行 <selectKey> 标签内的语句。

6.update标签

update 标签用于定义更新语句,执行更新操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。
(1)常用标签属性

注意:

insert 标签中没有 resultType及resultMap 属性,只有查询操作才需要对返回结果类型进行相应的指定。

传递参数的几种方式同select的一致。

(2)示例

int updateWebsite(String name);
<!--update 标签-->
<update id="updateWebsite" parameterType="string">
    update website set name = #{name}
</update>

7.delete标签

delete 标签用于定义 delete 语句,执行删除操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。

(1)常用标签属性

注意:

insert 标签中没有 resultType及resultMap 属性,只有查询操作才需要对返回结果类型进行相应的指定。

传递参数的几种方式同select的一致。

8.resultMap的特别说明

resultMap 是 MyBatis 中最复杂的元素,主要用于解决实体类属性名与数据库表中字段名不一致的情况,可以将查询结果映射成实体对象。

(1)构成

<resultMap id="" type="">
    <constructor><!-- 类再实例化时用来注入结果到构造方法 -->
        <idArg/><!-- ID参数,结果为ID -->
        <arg/><!-- 注入到构造方法的一个普通结果 --> 
    </constructor>
    <id/><!-- 用于表示哪个列是主键 -->
    <result/><!-- 注入到字段或JavaBean属性的普通结果 -->
    <association property=""/><!-- 用于一对一关联 -->
    <collection property=""/><!-- 用于一对多、多对多关联 -->
    <discriminator javaType=""><!-- 使用结果值来决定使用哪个结果映射 -->
        <case value=""/><!-- 基于某些值的结果映射 -->
    </discriminator>
</resultMap>
  • <resultMap> 元素的 type 属性表示需要的 POJO,id 属性是 resultMap 的唯一标识。
  • 子元素 <constructor> 用于配置构造方法。当一个 POJO 没有无参数构造方法时使用。
  • 子元素 <id> 用于表示哪个列是主键。允许多个主键,多个主键称为联合主键。
  • 子元素 <result> 用于表示 POJO 和 SQL 列名的映射关系。
  • 子元素 <association>、<collection> 和 <discriminator> 用在级联的情况下。关于级联的问题比较复杂,在后面进行介绍。

id 和 result 元素都有以下属性。常用的为前两个。

(2)示例

<!--使用自定义结果集类型 -->
<resultMap type="net.biancheng.po.Website" id="myResult">
    <!-- property 是 net.biancheng.po.Website 类中的属性 -->
    <!-- column是查询结果的列名,可以来自不同的表 -->
    <id property="id" column="id" />
    <result property="uname" column="name" />
</resultMap>

 resultMap 元素的属性 id 代表这个 resultMap 的标识,type 标识需要映射的 POJO。我们可以使用 MyBatis 定义好的类的别名或自定义类的全限定名。

这里使用 property 元素指定 Website 的属性名称 uname,column 表示数据库中 website 表的 SQL 列名 name,将 POJO 和 SQL 的查询结果一 一对应。

<select id="selectAllWebsite" resultMap="myResult">
    select id,name,url from website
</select>

可以发现 SQL 语句的列名和 myResult 中的 column 一一对应。resultMap的内容是上面定义中id的内容。

resultmap与resulttype的区别为:对象不同、描述不同、类型适用不同

一、对象不同

1、resultmap:resultMap如果查bai询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。

2、resulttype:resultType使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

二、描述不同

1、resultmap:resultMap对于一对一表连接的处理方式通常为在主表的pojo中添加嵌套另一个表的pojo,然后在mapper.xml中采用association节点元素进行对另一个表的连接处理。

2、resulttype:resultType无法查询结果映射到pojo对象的pojo属性中,根据对结构集查询遍历的需要选择使用resultType还是resultMap。

三、类型适用不同

1、resultmap:mybatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap。

2、resulttype:resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,但是resultType跟resultMap不能同时存在。

如果你要用resulttype返回一个复杂对象的话,就必须返回这个对象的所有属性。

说白了就是resultmap和resulttype都是作为sql的返回结果集,但是resultmap适用于pojo类和表字段不匹配以及复杂表的关联查询,不可以直接返回返回类型必须是外部自己定义的resultmap的引用但是resultType可以直接返回返回类型,但是实体类对应关系一定要名字完全对应。当然resulttype也可以实现关联查询的只是这需要思考出方法来实现。

9.注解

常用注解有@Param,其他注解不常用,暂不介绍。

10.关联(级联)查询

级联关系是一个数据库实体的概念,有 3 种级联关系,分别是一对一级联、一对多级联以及多对多级联。

  • 一对多的关系,如角色和用户的关系。通俗的理解就是,一家软件公司会存在许多软件工程师,公司和软件工程师就是一对多的关系。
  • 一对一的关系。每个软件工程师都有一个编号(ID),这是他在公司的标识,它与工程师是一对一的关系。
  • 多对多的关系,有些公司一个角色可以对应多个用户,但是一个用户可以兼任多个角色。通俗的说,一个人既可以是总经理,同时也是技术总监,而技术总监这个职位可以对应多个人,这就是多对多的关系。

(1)一对一关联查询

在 <association> 元素中通常使用以下属性。

  • property:指定映射到实体类的对象属性。
  • column:指定表中对应的字段(即分布查询的查询条件)。
  • javaType:指定映射到实体对象属性的类型。
  • select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。

一对一关联查询可采用以下两种方式:

  • 单步查询,通过关联查询实现
  • 分步查询,通过两次或多次查询,为一对一关系的实体 Bean 赋值

单步查询:

实体类:

ackage net.biancheng.po;
public class Student {
    private int id;
    private String name;
    private int sex;
    private StudentCard studentCard;
    /*省略setter和getter方法*/
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", studentCard=" + studentCard + "]";
    }
}
<resultMap type="net.biancheng.po.Student" id="cardAndStu2">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="sex" column="sex" />
    <!-- 一对一级联查询 -->
    <association property="studentCard"
        javaType="net.biancheng.po.StudentCard">
        <id property="id" column="id" />
        <result property="studentId" column="studentId" />
    </association>
</resultMap>
<select id="selectStuById2" parameterType="Integer"
    resultMap="cardAndStu2">
    SELECT s.*,sc.studentId FROM student s,studentCard sc
    WHERE
    s.cardId = sc.id AND s.id=#{id}
</select>

 通过两个表的连接查出来两个表的数据,在association标签中,property的内容是实体类中属性名,javaType是指属性名对应的类型。后面的则是实体类中的属性。

分布查询:

<mapper namespace="net.biancheng.mapper.StudentCardMapper">
    <select id="selectStuCardById"
        resultType="net.biancheng.po.StudentCard">
        SELECT * FROM studentCard WHERE id = #{id}
    </select>
</mapper>
<mapper namespace="net.biancheng.mapper.StudentMapper">
    <!-- 一对一根据id查询学生信息:级联查询的第一种方法(嵌套查询,执行两个SQL语句) -->
    <resultMap type="net.biancheng.po.Student" id="cardAndStu1">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="sex" column="sex" />
        <!-- 一对一级联查询 -->
        <association property="studentCard" column="cardId"
            javaType="net.biancheng.po.StudentCard"
            select="net.biancheng.mapper.StudentCardMapper.selectStuCardById" />
    </resultMap>
    <select id="selectStuById1" parameterType="Integer"
        resultMap="cardAndStu1">
        select * from student where id=#{id}
    </select>
</mapper>

property:设置属性名。

javaType:设置属性类型。

column:设置查询条件。

select:设置查询语句。

(2)一对多关联查询

在 MyBatis 中,通过 <resultMap> 元素的子元素 <collection> 处理一对多级联关系,collection 可以将关联查询的多条记录映射到一个 list 集合属性中。示例代码如下。

<collection property="orderList"
        javaType="net.biancheng.po.Order" column="id"
        select="net.biancheng.mapper.OrderMapper.selectOrderById" />

在 <collection> 元素中通常使用以下属性。

  • property:指定映射到实体类的对象属性。
  • column:指定表中对应的字段(即分布查询的查询条件)。
  • javaType:指定映射到实体对象属性的类型。
  • select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。

一对多关联查询可采用以下两种方式:

  • 分步查询,通过两次或多次查询,为一对多关系的实体 Bean 赋值
  • 单步查询,通过关联查询实现

单步查询:

ackage net.biancheng.po;
import java.util.List;
public class User {
    private int id;
    private String name;
    private String pwd;
    private List<Order> orderList;
    /*省略setter和getter方法*/
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", orderList=" + orderList + "]";
    }
}
<!-- 一对多 根据id查询用户及其关联的订单信息:级联查询的第二种方法(单步查询) -->
<resultMap type="net.biancheng.po.User" id="userAndOrder2">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="pwd" column="pwd" />
    <!-- 一对多级联查询,ofType表示集合中的元素类型 -->
    <collection property="orderList"
        javaType="net.biancheng.po.Order">
        <id property="oId" column="oId" />
        <result property="ordernum" column="ordernum" />
    </collection>
</resultMap>
<select id="selectUserOrderById2" parameterType="Integer"
    resultMap="userAndOrder2">
    SELECT u.*,o.id as oId,o.ordernum FROM `user` u,`order` o
    WHERE
    u.id=o.`userId` AND u.id=#{id}
</select>

 分布查询:

<!-- 根据id查询订单信息 -->
<select id="selectOrderById" resultType="net.biancheng.po.Order"
    parameterType="Integer">
    SELECT * FROM `order` where userId=#{id}
</select>
<!-- 一对多 根据id查询用户及其关联的订单信息:级联查询的第一种方法(分步查询) -->
<resultMap type="net.biancheng.po.User" id="userAndOrder1">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="pwd" column="pwd" />
    <!-- 一对多级联查询,ofType表示集合中的元素类型,将id传递给selectOrderById -->
    <collection property="orderList"
        javaType="net.biancheng.po.Order" column="userId"
        select="net.biancheng.mapper.OrderMapper.selectOrderById" />
</resultMap>
<select id="selectUserOrderById1" parameterType="Integer"
    resultMap="userAndOrder1">
    select * from user where id=#{id}
</select>

各属性说明和一对多查询一致。

分布查询的好处在于可以实现延迟加载。开启延迟加载之后会根据你要获取的信息来执行对应的sql,如上面的sql一部分是获取用户的信息,一部分是获取订单的信息,如果实际代码中只使用了用户的信息,则获取订单信息的sql则不会执行。

开启延迟加载的配置:

<setting name="lazyLoadingEnabled” value="true"/>

开启延迟加载的场合,也可以在association或collection中通过属性设置个别sql是延迟加载还是立即加载。

延迟加载:

 立即加载:

(3)多对多关联查询

实际应用中,由于多对多的关系比较复杂,会增加理解和关联的复杂度,所以应用较少。MyBatis 没有实现多对多级联,推荐通过两个一对多级联替换多对多级联,以降低关系的复杂度,简化程序。

11.动态sql

动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,开发人员通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。例如,拼接时要确保添加了必要的空格,还要注意去掉列表最后一个列名的逗号。而动态 SQL 恰好解决了这一问题,可以根据场景动态的构建查询。

(1)if标签

MyBatis if 类似于 Java 中的 if 语句,是 MyBatis 中最常用的判断语句。使用 if 标签可以节省许多拼接 SQL 的工作,把精力集中在 XML 的维护上。

语法:

<if test="判断条件">
    SQL语句
</if>

 当判断条件为 true 时,才会执行所包含的 SQL 语句。

示例:

<select id="selectAllWebsite" resultMap="myResult">
    select id,name,url from website where 1=1
    <if test="name != null">
        AND name like #{name}
    </if>

    <if test="url!= null">
        AND url like #{url}
    </if>
</select>

多个if可以公用,也可以嵌套使用。

(2) choose-when-otherwise标签

MyBatis 中动态语句 choose-when-otherwise 类似于 Java 中的 switch-case-default 语句。由于 MyBatis 并没有为 if 提供对应的 else 标签,如果想要达到<if>...<else>...</else> </if> 的效果,可以借助 <choose>、<when>、<otherwise> 来实现。
语法:

<choose>
    <when test="判断条件1">
        SQL语句1
    </when >
    <when test="判断条件2">
        SQL语句2
    </when >
    <when test="判断条件3">
        SQL语句3
    </when >
    <otherwise>
        SQL语句4
    </otherwise>
</choose>

choose 标签按顺序判断其内部 when 标签中的判断条件是否成立,如果有一个成立,则执行相应的 SQL 语句,choose 执行结束;如果都不成立,则执行 otherwise 中的 SQL 语句。这类似于 Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。

示例:

<mapper namespace="net.biancheng.mapper.WebsiteMapper">
    <select id="selectWebsite"
        parameterType="net.biancheng.po.Website"
        resultType="net.biancheng.po.Website">
        SELECT id,name,url,age,country
        FROM website WHERE 1=1
        <choose>
            <when test="name != null and name !=''">
                AND name LIKE CONCAT('%',#{name},'%')
            </when>
            <when test="url != null and url !=''">
                AND url LIKE CONCAT('%',#{url},'%')
            </when>
            <otherwise>
                AND age is not null
            </otherwise>
        </choose>
    </select>
</mapper>

(3)where标签

where 标签主要用来简化 SQL 语句中的条件判断,可以自动处理 AND/OR 条件。

语法:

<where>
    <if test="判断条件">
        AND/OR ...
    </if>
</where>

if 语句中判断条件为 true 时,where 关键字才会加入到组装的 SQL 里面,否则就不加入。where 会检索语句,它会将 where 后的第一个 SQL 条件语句的 AND 或者 OR 关键词去掉。

示例:

<select id="selectWebsite" resultType="net.biancheng.po.Website">
    select id,name,url from website
    <where>
        <if test="name != null">
            AND name like #{name}
        </if>
        <if test="url!= null">
            AND url like #{url}
        </if>
    </where>
</select>

(4)set标签

在 Mybatis 中,update 语句可以使用 set 标签动态更新列。set 标签可以为 SQL 语句动态的添加 set 关键字,剔除追加到条件末尾多余的逗号。

语法:

        <set>
            <if test="name!=null">name=#{name},</if>
            <if test="url!=null">url=#{url},</if>
        </set>

示例:

<?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="net.biancheng.mapper.WebsiteMapper">
    <!--使用set元素动态修改一个网站记录 -->
    <update id="updateWebsite"
        parameterType="net.biancheng.po.Website">
        UPDATE website
        <set>
            <if test="name!=null">name=#{name},</if>
            <if test="url!=null">url=#{url},</if>
        </set>
        WHERE id=#{id}
    </update>
</mapper>

(4)foreach标签

对于一些 SQL 语句中含有 in 条件或者是批量插入多条数据的场合,需要迭代条件集合来生成的情况,可以使用 foreach 来实现 SQL 条件的迭代。 

Mybatis foreach 标签用于循环语句,它很好的支持了数组和 List、set 接口的集合,并对此提供遍历的功能。

语法:

<foreach item="item" index="index" collection="list|array|map key" open="(" separator="," close=")">
    参数值
</foreach>

foreach 标签主要有以下属性,说明如下。

  • item:表示集合中每一个元素进行迭代时的别名。
  • index:指定一个名字,表示在迭代过程中每次迭代到的位置。
  • open:表示该语句以什么开始(既然是 in 条件语句,所以必然以(开始)。
  • separator:表示在每次进行迭代之间以什么符号作为分隔符(既然是 in 条件语句,所以必然以,作为分隔符)。
  • close:表示该语句以什么结束(既然是 in 条件语句,所以必然以)开始)。

使用 foreach 标签时,最关键、最容易出错的是 collection 属性,该属性是必选的,但在不同情况下该属性的值是不一样的,主要有以下 3 种情况:

  • 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list。
  • 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array。
  • 如果传入的参数是多个,可以把它们封装成一个 Map,当然单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。
  • 如果参数使用了@Param注解,collection 属性值为注解的名字,如果是一个javabean,collection 属性值为注解的名字.list的名字或者注解的名字.array的名字。

(5)bind标签

每个数据库的拼接函数或连接符号都不同,例如 MySQL 的 concat 函数、Oracle 的连接符号“||”等。这样 SQL 映射文件就需要根据不同的数据库提供不同的实现,显然比较麻烦,且不利于代码的移植。幸运的是,MyBatis 提供了 bind 标签来解决这一问题。

bind 标签可以通过 OGNL 表达式自定义一个上下文变量。        

语法:

<select id="selectWebsite" resultType="net.biancheng.po.Website">
    <bind name="pattern" value="'%'+parameter+'%'" />
    SELECT id,name,url,age,country
    FROM website
    WHERE name like #{pattern}
</select>

bind 元素属性如下。

  • value:对应传入实体类的某个字段,可以进行字符串拼接等特殊处理。
  • name:给对应参数取的别名。

以上代码中的“parameter”代表传递进来的参数,它和通配符连接后,赋给了 pattern,然后就可以在 select 语句中使用这个变量进行模糊查询,不管是 MySQL 数据库还是 Oracle 数据库都可以使用这样的语句,提高了可移植性。

示例:

<select id="selectWebsite" resultType="net.biancheng.po.Website">
    <bind name="pattern_name" value="'%'+name+'%'" />
    <bind name="pattern_url" value="'%'+url+'%'" />
    SELECT id,name,url,age,country
    FROM website
    WHERE name like #{pattern_name}
    AND url like #{pattern_url}
</select>

(6)trim标签

在 MyBatis 中除了使用 if+where 实现多条件查询,还有一个更为灵活的元素 trim 能够替代之前的做法。
trim 一般用于去除 SQL 语句中多余的 AND 关键字、逗号或者给 SQL 语句前拼接 where、set 等后缀,可用于选择性插入、更新、删除或者条件查询等操作。

语法:

<trim prefix="前缀" suffix="后缀" prefixOverrides="忽略前缀字符" suffixOverrides="忽略后缀字符">
    SQL语句
</trim>

属性说明:

 示例:

 trim 实现与 where 元素相同的效果

<select id="selectWebsite" resultType="net.biancheng.po.Website">
    SELECT id,name,url,age,country
    FROM website
    <trim prefix="where" prefixOverrides="and">
        <if test="name != null and name !=''">
            AND name LIKE CONCAT ('%',#{name},'%')
        </if>
        <if test="url!= null">
            AND url like concat ('%',#{url},'%')
        </if>
    </trim>
</select>

 trim 实现与 set 元素相同的效果

    <update id="updateBmsBillMemo" parameterType="BmsBillMemo">
        update bms_bills_memo      
          <trim prefix="SET" suffixOverrides=",">
            <if test="supplierId != null">supplier_id =
                #{supplierId},
            </if>
            <if test="supplierName != null">supplier_name =
                #{supplierName},
            </if>
            <if test="delFlag != null">del_flag =
                #{delFlag},
            </if>
          </trim>
        where id = #{id}
    </update>

trim用于插入

    <insert id="insertBmsBillMemo" parameterType="BmsBillMemo" useGeneratedKeys="true"
            keyProperty="id">
        insert into bms_bills_memo
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="supplierId != null">supplier_id,
            </if>
            <if test="supplierName != null">supplier_name,
            </if>
            <if test="clientId != null">client_id,
            </if>
            <if test="clientName != null and clientName != ''">client_name,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="supplierId != null">#{supplierId},
            </if>
            <if test="supplierName != null">#{supplierName},
            </if>
            <if test="clientId != null">#{clientId},
            </if>
            <if test="clientName != null and clientName != ''">#{clientName},
            </if>
        </trim>
    </insert>

(7)sql和include标签

定义和引用标签,当同一个mapper下的很多方法都会用到一些查询字段,或者where条件。将其定义为常量,提高代码的复用性和可读性。

示例:

 <!-- 查询字段 -->
    <sql id="Base_Column_List">
        ID,MAJOR,BIRTHDAY,AGE,NAME,HOBBY
    </sql>
    
    <select id="selectStudent" resultMap="com.example.demo.entity.Student">
        SELECT
        <include refid="Base_Column_List" />
        FROM
        student
        <include refid="Example_Where_Clause" />
    </select>

12.mybatis分页

MyBatis 的分页功能是基于内存的分页,即先查询出所有记录,再按起始位置和页面容量取出结果。

/**
*
* @param site
* @param currentPageNo 起始位置
* @param pageSize      页面容量
* @return
*/
public List<Website> selectWebsite(@Param("site") Website site, @Param("from") Integer currentPageNo,
        @Param("pageSize") Integer pageSize);
<select id="selectWebsite" resultType="net.biancheng.po.Website">
    SELECT id,name,url,age,country
    FROM website
    <trim prefix="where" prefixOverrides="and">
        <if test="site.name != null and site.name !=''">
            AND name LIKE CONCAT ('%',#{site.name},'%')
        </if>
        <if test="site.url!= null and site.url !=''">
            AND url LIKE CONCAT ('%',#{site.url},'%')
        </if>
        ORDER BY id limit #{from},#{pageSize}
    </trim>
</select>

相比原来的 selectWebsite 方法,增加了两个参数,起始位置(from)和页面容量(pageSize)。

查询语句中增加 limit 关键字。现在基本使用第三方分页工具进行分页,如pageHelper。

13缓存

缓存可以将数据保存在内存中,是互联网系统常常用到的。目前流行的缓存服务器有 MongoDB、Redis、Ehcache 等。缓存是在计算机内存上保存的数据,读取时无需再从磁盘读入,因此具备快速读取和使用的特点。
和大多数持久化框架一样,MyBatis 提供了一级缓存和二级缓存的支持。默认情况下,MyBatis 只开启一级缓存。

一级缓存:

级缓存是基于 PerpetualCache(MyBatis自带)的 HashMap 本地缓存,作用范围为 session 域内。当 session flush(刷新)或者 close(关闭)之后,该 session 中所有的 cache(缓存)就会被清空。

在参数和 SQL 完全一样的情况下,我们使用同一个 SqlSession 对象调用同一个 mapper 的方法,往往只执行一次 SQL。因为使用 SqlSession 第一次查询后,MyBatis 会将其放在缓存中,再次查询时,如果没有刷新,并且缓存没有超时的情况下,SqlSession 会取出当前缓存的数据,而不会再次发送 SQL 到数据库。

由于 SqlSession 是相互隔离的,所以如果你使用不同的 SqlSession 对象,即使调用相同的 Mapper、参数和方法,MyBatis 还是会再次发送 SQL 到数据库执行,返回结果。

二级缓存:

二级缓存是全局缓存,作用域超出 session 范围之外,可以被所有 SqlSession 共享。
一级缓存缓存的是 SQL 语句,二级缓存缓存的是结果对象。

MyBatis 的全局缓存配置需要在 mybatis-config.xml 的 settings 元素中设置,代码如下。

<settings>
    <setting name="cacheEnabled" value="true" />
</settings>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis学习笔记:数据结构和命令

本文是自己的学习笔记。主要参考资料如下&#xff1a; 马士兵 4、Redis的五大数据类型1.1、String1.1.1、String 类型的命令1.1.2、存储对象1.2、List1.2.1、List基本命令1.2.2、List高级命令1.3、Set1.3.1、Set基本命令1.4、HashMap1.4.1、HashMap基本命令1.5、ZSet&#xff0…

【数据结构】7.4 散列表的查找

文章目录7.4.1 散列表的基本概念7.4.2 散列函数的构造散列函数的构造方法7.4.3 处理冲突的方法1. 开地址法1.1 线性探测法1.2 二次探测法2. 链地址法7.4.4 散列表的查找散列表的查找效率分析总结7.4.1 散列表的基本概念 基本思想&#xff1a;根据要存储的关键字的值&#xff0…

计算机网络-杂项

目录 1、蜂窝移动网络 2、TCP和UDP 3、5层架构 4、在浏览器中输入url地址显示主页的过程 5、TCP的基本操作 6、三次握手&#xff0c;四次挥手 6.1、三次握手&#xff1a;双方保证自己和对方都能接收和发送数据。 6.2、三次握手中&#xff0c;为什么客户机最后还要再向服…

【计算机网络】应用层体系

我们知道现代常用的计算机网络模型为5层模型&#xff0c;其中应用层是直接与我们平时常见的软件对接的最高层&#xff0c;所以先来学习应用层就显得很有必要了。其中在应用层我们需要学习网络应用程序的实现、原理并且了解网络应用程序所需要的网络服务、客户和服务器、进程和运…

DW 2023年1月Free Excel 第七次打卡 动态函数

第七章 Excel函数-动态函数 数据下载地址与参考链接&#xff1a;https://d9ty988ekq.feishu.cn/docx/Wdqld1mVroyTJmxicTTcrfXYnDd 1.FILTER函数 在工作中&#xff0c;根据指定的条件&#xff0c;将符合条件的所有记录从数据源表格式查找过来&#xff0c;一是可以用高级筛选。…

两个实用的shell命令:sed和awk用法

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 本文目录 sed的用法 sed常用场景 awk的用法 awk常用场景 我们先来看一下力扣上的shell题库中的一题&#xff1a; 实现这个功能一般来说我们会想到tail和head命令来指定打印前几行或者后几…

string的模拟实现(下)

目录 string的模拟实现下 析构函数&#xff1a; 完善函数 空对象的构造函数&#xff1a; 头插函数的一些修正&#xff1a; 构造函数的完善&#xff1a; 实现append 插入函数&#xff1a; 插入函数(字符串&#xff09; erase删除函数&#xff1a; 实现find函数&#…

【读论文】Spiking-YOLO Spiking Neural Network for Energy-Efficient Object Detection

AAAI-20 摘要 本文提出两个新方法为深度SNN提供快速、准确的信息传递&#xff1a;通道归一化和具有不平衡阈值的带符号神经元&#xff1b;本文也提出了一个基于脉冲的目标检测模型&#xff1a;Spiking-YOLO&#xff0c;并且在non-trivial datasets, PASCALVOC 和 MS COCO数据…

指针与数组

目录指针运算&#xff08;补&#xff09;指针指针指针的关系运算&#xff08;补&#xff09;指针与数组数组名二级指针指针数组指针运算&#xff08;补&#xff09; 指针指针 上一篇博客我们介绍了指针运算中的三种常见运算&#xff1a;指针整数&#xff0c;指针关系运算&…

23.1.27打卡 Codeforces Round #846 (Div. 2) A~D

https://codeforces.com/contest/1780A题给你一个长度为n的数组, 问你是否能找出三个数字, 使得这三个数字之和为奇数简单的小学数学奇偶奇偶偶偶所以我们只要找到三个奇数或者两个偶数一个奇数就好了/* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿…

简单复现 残差网络、Googlenet、mobilenet、SqueezeNet、ShuffleNet

1.残差网络 1&#xff09;网络结构 当对x求偏导的时候&#xff0c;F&#xff08;x&#xff09;对x求偏导的值很小的时候&#xff0c;对整体求x的偏导会接近于1 这样解决了梯度消失问题&#xff0c;我们可以对离输入很近的层进行很好的更新。 要注意的是F&#xff08;x&#…

【REACT-redux】

1. redux介绍 1.1 描述 Redux最主要是用作应用状态的管理。简言之&#xff0c;Redux用一个单独的常量状态树&#xff08;state对象&#xff09;保存这一整个应用的状态&#xff0c;这个对象不能直接被改变。当一些数据变化了&#xff0c;一个新的对象就会被创建&#xff08;使…

JDK SPI 和 Dubbo SPI

SPI &#xff08;Service Provider Interface&#xff09;&#xff0c;简单翻译就是服务提供接口&#xff0c;这里的“服务”泛指任何一个可以提供服务的功能、模块、应用或系统&#xff0c;会预留一些口子或者扩展点&#xff0c;只要按照既定的规范去开发&#xff0c;就可以动…

MES和金蝶云星空接口打通对接实战

四化智造MES&#xff08;WEB&#xff09;和金蝶云星空接口打通对接实战数据源平台:四化智造MES&#xff08;WEB&#xff09;MES建立统一平台上通过物料防错防错、流程防错、生产统计、异常处理、信息采集和全流程追溯等精益生产和精细化管理&#xff0c;帮助企业合理安排生产排…

机器视觉_HALCON_HDevelop用户指南_2.Getting Started

文章目录前言二、Getting Started2.1. 运行HDevelop2.2. 运行示例程序前言 标题本来想用“开始使用”或“快速上手”&#xff0c;不过感觉怪怪的&#xff0c;干脆就叫Getting Started吧&#xff0c;因为许多开发手册&#xff0c;开始上手的那节就叫这个名字。 本文是接上一篇…

【人工智能原理自学】LSTM网络:自然语言处理实践

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解LSTM网络&#xff1a;自然语言处理实践&#xff0c;一起卷起来叭&#xff01; 目录一、“RNN”二、编程实验一、“RNN” 上节课我们利用词嵌入把句子转化为词向量序列…

手把手本地搭建服务器笔记1

需要的下载的东西&#xff1a; vmware (百度网盘)银河麒麟镜像xshell,xftp安装vmware&#xff1a; 下载的包里有密钥&#xff0c;安装的时候就直接把密钥扔里面就好了 镜像处理&#xff1a; vmware左上角文件-新建虚拟机-典型&#xff0c;下一步 -安装程序光盘映像文件&am…

基于嵌入式物联网技术的智慧病房方案设计

文章目录前言1、要求2、系统设计3、功能模块3、系统功能模块图一、stm32控制模块原理图二、各功能模块的实现1、整个系统的基本配置2、RTOS多任务1、设计线程2、配置主函数代码3、温湿度读取模块(I2C)4、LED定时开关灯(pwm)5、按键实现报警信号6、脉搏&血氧数据读取7、UART…

【HTML】基础的入门学习

HTML 菜鸟教程 简介 一般结构&#xff1a; <!DOCTYPE html> 声明为 HTML5 文档<html> 元素是 HTML 页面的根元素<head> 元素包含了文档的元&#xff08;meta&#xff09;数据&#xff0c;如 <meta charset"utf-8"> 定义网页编码格式为 ut…

proteus仿真软件中芯片的命名规则与封装方法(详细版)

第一&#xff1a;PCB封装库命名规则 1、集成电路&#xff08;直插&#xff09; 用DIP-引脚数量尾缀来表示双列直插封装​ 尾缀有N和W两种,用来表示器件的体宽​ 为体窄的封装&#xff0c;体宽300mil,引脚间距2.54mm​ 为体宽的封装, 体宽600mil,引脚间距2.54mm​ 如&#…