MyBatis框架

MyBatis框架

一.概述

Mybatis是一款一流的支持自定义SQL,储存过程和高级映射的持久化框架。MyBatis 几乎消除了所有的 JDBC 代码,也基本不需要手动设置参数以及获取结果集。 MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录,是一种 ORM(ORM Object Relational Mapping 对象关系映射)实现.

Mybatis是一款一流的支持自定义sql,储存过程和高级映射的持久化框架。Mybatis几乎笑出了所有的JDBC代码,也基本不需要收到设置参数以及获取结果集,MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和java的POJO(plain Old java Objects 普通的java对象),映射成数据库中的记录,是一种ORMObject Relational Mapping 对象关系映射 实现

二.传统jdbc编程

1、 加载数据库驱动

2、 创建并获取数据库链接

3、 创建 statement 对象

4、 拼写 sql 语句

5、 设置 sql 语句中的占位符的值

6、 执行 sql 语句并获取结果

7、 对 sql 执行结果进行解析处理

8、 释放资源

jdbc编程问题:

1.数据库连接的创建,释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决问题

2.SQL语句编写在java代码中,这种编码造成代码不易维护,当SQL变动时需要修改java源代码。

3.使用perparedStatement向占位符传参存在硬编码,因为SQL语句的where条件中占位符的个数可能发生变化,修改SQL还要修改java源代码,系统不易维护。

4.对结果集解析存在硬编码SQL语句变化导致解析代码变化,系统不易维护。

总结:1.浪费系统资源,2.系统和代码不易维护

三.MyBatis架构

MyBatis是优秀的持久层框架,它能够解决JDBC编程中存在的问题,以下是MyBatis的架构:

在这里插入图片描述

四.三层架构

三层分别为数据访问层(DAL)、业务逻辑层(BLL)、表示层(UI)在三层架构中将用户接口,商业逻辑,数据保存以及数据访问设计为三个独立的模块,使得每个层可以被单独开发,单独测试,而不影响其它层。也就是说,分层的核心目的是满足开发过程中的“高内聚、低耦合”原则。

值得注意的是,这里的三层是指逻辑上的三层,也不仅仅有B/S应用才是三层体系结构。下面是三层的结构示意图:

在这里插入图片描述

五.MyBatis环境搭建

MyBatis搭建流程:
1.导入mybatis jar mysql驱动
2.配置mybatis核心配置文件
3.创建表, 对应的类
4.创建映射接口(主要用于定义有哪些操作)
5.创建sql映射配置文件( sql实现 )
6.测试
读取核心配置文件
创建SqlSessionFactory
创建SqlSession
获得接口代理对象
代理对象.接口中的方法

1.导入Mybatis jar包数据驱动包

<dependency>
    <groupId>org.mybatis</groupId> 
    <artifactId>mybatis</artifactId> 
    <version>3.4.2</version> 
</dependency>

注:是通过Maven导入的

在这里插入图片描述

Mybatis 源码下载

2.创建Mybatis全局配置文件

MyBatis 的配置文件包含了对 MyBatis 行为的设置信息。 配置文档的顶层 结构如下(标签需要按照特定顺序排放):

在这里插入图片描述

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value=""/>
                <property name="url" value=""/>
                <property name="username" value=""/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/sxt/mybatisDemo/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

代码示例:

<?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">
<!--
mybatis核心配置文件
-->
<configuration>
    <!--引入存放-->
    <properties resource="config.properties"></properties>

    <!--全局配置-->
    <settings>
        <!--配置日志实现  使用log4j  添加日志组件  导入jar包  配置属性文件-->
        <setting name="logImpl" value="LOG4J"/>

        <!--开启驼峰自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--为类定义别名-->
    <typeAliases>
        <typeAlias type="com.ffyc.mybatispro.model.Admin" alias="Admin"></typeAlias>
        <typeAlias type="com.ffyc.mybatispro.model.Emloyee" alias="Emloyee"></typeAlias>
        <typeAlias type="com.ffyc.mybatispro.model.Dept" alias="Dept"></typeAlias>
    </typeAliases>


    <!--
    environments  配置与数据库连接的相关信息
    后面将spring(管家),spring整合管理mybatis,配置会发生变化
    -->
    <environments default="development">
        <!--配置本地开发信息-->
        <environment id="development">
            <!--事务:一次对数据库操作的若干个流程管理,对整个流程安全的确保-->
            <!--配置事务管理类型,使用JDBC事务管理
            事务:一次对数据库操作的若干个流程  如:转账A-B  (A-100 B+100)
            -->
            <transactionManager type="JDBC"></transactionManager>

            <!--数据源
            type="UNPOOLED" UNPOOLED不使用数据库连接池   POOLED使用数据库连接池
            -->
            <dataSource type="POOLED">
                <!--数据库驱动-->
                <property name="driver" value="${driver}"/>
                <!--数据库地址-->
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--例如work配置生产环境信息
      <environment id="work">
    <transactionManager type="JDBC"></transactionManager>
    <dataSource type="POOLED"></dataSource>
       </environment>
    -->

    <!--添加sql映射文件-->
    <mappers>
        <mapper resource="mapper/AdminMapper.xml"/>
        <mapper resource="mapper/EmolyeeMapper.xml"/>
        <mapper resource="mapper/DeptMapper.xml"/>
    </mappers>
</configuration>

在这里插入图片描述

数据库连接池【重要】:后面补充

3.创建sql映射文件

MyBatis 真正强大之处就在这些映射语句,也就是它的魔力所在。对于它的强大功能,SQL 映 射文件的配置却非常简单。如果比较 SQL 映射文件配置与 JDBC 代码,很快可以发现,使用 SQL 映射文件配置可以节省 95%的代码量。MyBatis 被创建来专注于 SQL,但又给自己的实现极 大的空间

创建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.ff.mybatis.dao.UserDao">
    
</mapper>

sql映射文件中的标签:

  • insert –INSERT 映射语句
  • update –UPDATE 映射语句
  • delete –DELEETE 映射语句
  • select –SELECT 映射语句
  • resultMap – 最复杂也是最强大的元素,用来描述如何从数据库结果集里加载对象。

insert-插入数据:

<insert id(它的值是为对应映射接口的方法名)="唯一标识" useGeneratedKeys="把新增加的主键赋值到自己定义的 keyProperty " keyProperty= 接收主键的属性 parameterType="接收的参数类型"> 
        insert into user(userName,userAge)values(#{userName},#{userAge}) 
</insert> 

update-修改数据:

<update id(它的值是为对应映射接口的方法名)="唯一标识" parameterType="接收的参数类型">
    update ts_user set userName = #{userName},userAge = #{userAge}
              where userId = #{userId}
</update>

delete-删除数据:

<delete id(它的值是为对应映射接口的方法名)="唯一标识" parameterType="接收的参数类型"> 
    delete from ts_user where userId = #{id} 
</delete>

select-查询数据:

<select id(它的值是为对应映射接口的方法名)="唯一标识" resultType="返回结果集类型"> 
    select * from ts_user where id= #{id}
</select>

resultMap-– 最复杂也是最强大的元素,用来描述如何从数据库结果集里加载对象,数据库列名与java类的属性名不一样用来解决列名与属性名的映射问题:

 <!--
      特殊情况下,列名与属性名就是不一致,  怎么解决映射问题
      resultMap 结果集映射
    -->

 <resultMap id="adminMap" type="Admin">
     <id column="id" property="id" ></id>
     <result column="account" property="account"></result>
     <result column="pass_word" property="passWord"></result>
     <result column="sex" property="sex1"></result>
  </resultMap>

 <select id="getAdminById" resultMap="adminMap">
    select * from admin where id = #{id}
 </select>

 <select id="getAdmin" resultType="Admin">
      select  * from admin where account=#{acc} and sex = #{sex}
 </select>

图片示例:

在这里插入图片描述

补充:

useGeneratedKeys=“true” 可以返回刚插入数据的主键

keyColumn="id"告知主键列

keyProperty=“id” 告知与主键列对应的属性

做这些操作可以在像数据库传递数据的同时将数据表中的主键封装到对应的java对象中

面试必问【重要】

#{属性名} values(?,?,?) 赋值方式时预编译的, 安全的 可以防止sql注入

${属性}values(‘admin2’,‘111’,‘男’) 字符串拼接方式 ${} 多用来传列名,而不是传数据

代码示例:

<?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">
 <!--
 namespace="某个接口的名称"
 -->
<mapper namespace="com.ffyc.mybatispro.mapper.AdminMapper">
    <!--
     parameterType="参数类型"
     #{属性名} values(?,?,?) 赋值方式时预编译的, 安全的 可以防止sql注入
     ${属性}values('admin2','111','男')  字符串拼接方式
          ${} 多用来传列名,而不是传数据
          select ${column1},${column2}   from admin order by ${column}
          useGeneratedKeys="true" 可以返回刚插入数据的主键
          keyColumn="id"   告知主键列
          keyProperty="id" 告知与主键列对应的属性
    -->
  <insert id="saveAdmin" parameterType="Admin" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
      insert into admin(account,password,sex)values(#{account},#{password},#{sex})
  </insert>

  <update id="updateAdmin" parameterType="Admin">
      update admin  set account=#{account},
                        password=#{password},
                        sex=#{sex}
                        where id = #{id}
  </update>

  <delete id="deleteAdmin">
      delete from admin where id = #{id}
  </delete>

    <!--
      resultType="Admin" 返回值的类型  根据返回值类型 创建一个对象
      将数据库数据自动映射到java对象中,有前提表中的列名与类中的属性名相同
      开启驼峰命名自动映射 从数据库命名转java驼峰命名  user_name - userName

      特殊情况下,列名与属性名就是不一致,  怎么解决映射问题
      resultMap 结果集映射
    -->

 <resultMap id="adminMap" type="Admin">
     <id column="id" property="id" ></id>
     <result column="account" property="account"></result>
     <result column="pass_word" property="passWord"></result>
     <result column="sex" property="sex1"></result>
  </resultMap>
 <select id="getAdminById" resultMap="adminMap">
    select * from admin where id = #{id}
 </select>

 <select id="getAdmin" resultType="Admin">
      select  * from admin where account=#{acc} and sex = #{sex}
 </select>

    <!--
       java中已有的类作为类型使用时,可以直接使用mybatis定义好的别名
    -->
    <select id="getAdmin1" resultType="Admin" parameterType="hashmap">
        select  * from admin where account=#{acc} and sex = #{sex}
    </select>

    <select id="getAdminList" resultType="Admin">
        select * from admin
    </select>

    <!--
      resultType="int"
    -->
    <select id="getAdminCount"  resultType="int">
        select count(*) from admin
    </select>


</mapper>

4.Mybatis-Dao层 Mapper接口

Mapper 接口开发方法只需要程序员编写 Mapper 接口(相当于 Dao 接口),由 Mybatis 框架根据接口定义创建接口的动态代理对象. 使用 session.getMapper(接口.class);获得代理对象 Mapper 接口开发需要遵循以下

规范:

1、 Mapper.xml 文件中的 namespace 与 mapper 接口的类路径相同

2、 Mapper==接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同==

3、 Mapper 接口方法的==输入参数类型==和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同

4、 Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同

在这里插入图片描述

5.测试MyBatis

一整个流程:

读取配置文件

Reader reader = Resources.getResourceAsReader(“mybatis-config.xml”);

创建 SqlSessionFactory

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

创建 SqlSession

SqlSession sqlSession = sessionFactory.openSession();

SqlSessionFactory 接口 一旦创建,SqlSessionFactory 就会在整个应用过程中始终存在。所以没有理由 去销毁和再创建它,一个应用运行中也不建议多次创建 SqlSessionFactory。如 果真的那样做,会显得很耗时。

SqlSession 接口Sqlsession 意味着创建数据库会话,该接口中封装了对数据库操作的方法,与

数 据 库 会 话 完 成 后 关 闭 会 话 。 mybatis 中 使 用 SqlsessionFactory 的 openSession 方法创建。

Sqlsession 中的方法:

getMapper(Class class);获得接口代理对象

commit();提交事物

close();关闭

代码示例:

package com.ffyc.mybatispro.Test;

import com.ffyc.mybatispro.mapper.AdminMapper;
import com.ffyc.mybatispro.model.Admin;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.Reader;


public class Test1 {
@Test
    public static void main(String[] args) throws IOException, IOException {

        Admin admin = new Admin();
        admin.setAccount("admin1");
        admin.setPassWord("111");
        admin.setSex1("男");

            /*
            读取mybatis核心配置文件
             */
        Reader reader = Resources.getResourceAsReader("mybatisConf.xml");

            /*
             创建SqlSessionFactory对象
              创建SqlSession的工厂,负责创建SqlSeesion对象,SqlSessionFactory包含了核心配置信息
              由于SqlSeesionFactroy对象创建开销大,所以一旦创建就不用销毁,一个应用程序只有一个                     SqlSeesionFactory

             */
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);


        SqlSession sqlSession = sqlSessionFactory.openSession();
        /*
        创建SqlSeesion对象 表示一次与数据库链接会话  类似于JDBC中的Connection
        每与数据库交互一次,都会创建一个SqlSeesion对象,使用完后,就立即销毁
         */

        AdminMapper adminMapper = sqlSession.getMapper(AdminMapper.class);
        /*
        获得映射接口的代理对象
         */


        adminMapper.saveAdmin(admin);


        sqlSession.commit();

        sqlSession.close();
    }

}



6.MyBatis日志

MyBatis内置的日志工厂提供日志功能,具体的日志实现有以下几种方式:

SLF4J | LOG4J | LOG4J2 JDK_LOGGING

COMMONS_LOGGING STDOUT_LOGGING NO_LOGGING

具体选择哪个日志实现由 MyBatis 的内置日志工厂确定。它会使用最先找到的

配置日志:

(1)导入日志jar包:

在这里插入图片描述

(2)配置日志信息

在MyBatis全局配置文件中配置

<settings> 
    <setting name="logImpl" value="LOG4J"/> 
</settings>

在这里插入图片描述

结果输出的日志信息:

在这里插入图片描述

7.参数传递(简单,复杂)

向Mapper.xml文件中传递参数

简单参数传递:

简单的参数形式不需要使用 parameterType 参数定义,例如: User selectUsers(int id);

在这里插入图片描述

复杂参数传递:

(1)多个参数传递:

多个参数使用@Param(“id”)绑定

:User selectUsers(@Param(“id”)int id,@Param(“name”)String name);

<select id="selectUsers" resultType="User">
    select id, username, password from users where id = #{id}
</select>

再比如

在这里插入图片描述

(2)传入一个复杂的对象

如果传入一个复杂的对象,就需要使用 parameterType 参数进行接收的类型定义

:void insertUser(User user);

<insert id="insertUser" parameterType="User"> 
    insert into users (id, username, password) values (#{id}, #{username}, #{password}) </insert>

再比如

在这里插入图片描述

也可以使用 Map 对象传递

:void insertUser(Map<String,Object> map);

​ 在 sql 中使用表达式获取 map 的键即可

再比如
在这里插入图片描述

六.访问数据库时结果处理

1.简单类型输出映射

返回基本简单类型:

:public int findUserInfoCount();

<select id="findUserInfoCount" resultType="int">
    select count(*) from userInfo
</select>

再比如

int getAdminCount();                          //在Mapper接口中
<select id="getAdminCount"  resultType="int">   /*在Mapper.xml文件中*/
        select count(*) from admin
</select>

2.POJO 对象输出映射

如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装 到POJO(java普通)对象中.

如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以在全局MyBatis中设置实现自动转换

在这里插入图片描述

例:

在这里插入图片描述

3.resultMap【重要】

特殊情况下,列名与属性名就是不一致, 怎么解决映射问题 resultMap 结果集映射

定义result

<resultMap id="adminMap" type="Admin">
        <id column="id" property="id"></id>   <!--主键-->
        <result column="account" property="account"></result>   <!--普通列-->
        <result column="pass_word" property="passWord"></result>
        <result column="sex" property="sex1"></result>
    </resultMap>

(1). resutlMap 的 id 属性是 resutlMap 的唯一标识,本例中定义为 “useresultMap”

(2). resutlMap 的 itype属性是映射的 POJO (普通java类)类

(3). id 标签映射主键,result 标签映射非主键

(4). property 设置 POJO 的属性名称column 映射查询结果的列名称

使用result
在这里插入图片描述

七.多表关联处理结果集

resultMap 元素中 id,association , collection 元素

一般处理:

一对一:association – 复杂类型联合; 许多查询结果合成这个类型

​ 一对一结果映射– association 能引用自身, 或者从其它地方引用

​ association关联元素处理“有一个”类型的关系,即一对一关联。它有两种关联方式

​ (1)嵌套查询:通过另一个SQL映射语句来返回预期的复杂类型

		(2)嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集

复杂类型联合:

在这里插入图片描述

复杂类型关联查询代码:

<?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">
 <!--
 namespace="某个接口的名称"
 -->
<mapper namespace="com.ffyc.mybatispro.mapper.EmployeeMapper">

    <resultMap id="empmap" type="Employee">
        <id column="id" property="id"></id>
        <result column="ename" property="name"></result>
        <result column="age" property="age"></result>
        <!--封装部门信息-->
        <association property="dept" javaType="Dept">
             <result column="dname" property="name"></result>
        </association>
        <!--封装操作人信息-->
        <association property="admin" javaType="Admin">
            <result column="account" property="account"></result>
        </association>
    </resultMap>
    
    
    <select id="getEmployeeById" resultMap="empmap">
      SELECT
           emp.id,
           emp.name ename,
           emp.age,
           d.name dname,
           a.account
       FROM employee emp LEFT JOIN dept d ON emp.deptId = d.id
                         LEFT JOIN admin a ON emp.adminId = a.id
      WHERE emp.id = #{id}
    </select>

查询结果:

在这里插入图片描述

**多对一与一对多:**collection- 复杂类型集合

​ 嵌套结果映射- collection能引用自身,或者从其他地方引入

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">
 <!--
 namespace="某个接口的名称"
 -->
<mapper namespace="com.ffyc.mybatispro.mapper.DeptMapper">


    <resultMap id="deptmap" type="Dept">
        <id column="id" property="id"></id>
        <result column="dname" property="name"></result>
        <association property="admin" javaType="Admin">
            <result column="account" property="account"></result>
        </association>
        <collection property="employees" javaType="list" ofType="Employee">
             <result column="ename" property="name"></result>
        </collection>
    </resultMap>
    <select id="getDeptById" resultMap="deptmap">
            SELECT
                d.id,
                d.name dname,
                a.account,
                emp.name ename
             FROM dept d LEFT JOIN admin a ON d.adminId = a.id
                                 LEFT JOIN employee emp ON d.id = emp.deptId
                               WHERE d.id=#{id}
    </select>
    <select id="getDeptList" resultMap="deptmap">
        SELECT
                d.id,
                d.name dname,
                a.account,
                emp.name ename
             FROM dept d LEFT JOIN admin a ON d.adminId = a.id
                                 LEFT JOIN employee emp ON d.id = emp.deptId
    </select>
</mapper>

查询结果:

在这里插入图片描述

懒加载【重要】

需要查询关联信息时 使用MyBatis懒加载特性可有效的减少数据库压力,首次查询只查询主表信息,关联表的信息在用户获取再加载

配置打开懒加载:

Mybatis 默认没有打开懒加载配置,需要在 SqlMapperConfig.xml 中通过 settings 配置 (lazyLoadingEnabled 新版本就不用了Mapper.xml的fetchType 属性直接将它覆盖了),lazyLoadTriggerMethods来开启懒加载

在这里插入图片描述

collection 和 association 都需要配置 select 和 column 属性,两者配置方法相同

懒加载运行结果:

在这里插入图片描述

八.注解方式

建议简单sql使用注解方式

常用注解标签:

@Insert : 插入 sql , 和 xml insert sql 语法完全一样

@Select : 查询 sql, 和 xml select sql 语法完全一样

@Update : 更新 sql, 和 xml update sql 语法完全一样

@Delete : 删除 sql, 和 xml delete sql 语法完全一样

@Param : 入参

@Results : 设置结果集合

@Result : 结果

一个案例:

在这里插入图片描述

九.MyBatis动态SQL

MyBatis的一个强大特性之一通常是它的动态SQL能力。如果你有使用JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么 的痛苦,要确保不能忘记空格或者不要在 columns列后面省略一个逗号等。动态 SQL 可以彻解决这种痛苦

MyBatis 中用于实现动态 SQL 的元素主要有:

If

where

trim

set

choose (when, otherwise)

foreach

if:

if标签可以对传入的条件进行判断

在这里插入图片描述

where:

对于查询条件个数不确定的情况,可使用元素。如下:

  <select id="id" parameterType="“ resultType=""> 
    SELECT xxx... FROM table t
    <where>
        <if test="name != null">
            name like #{name}
        </if>
        <if test="value>0">
            AND name > #{value}
        </if>
    </where>
   </select>

元素会进行判断,如果它包含的标签中有返回值的话,它就插入一个 ‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头,它会剔除掉 AND 或 OR

trim:

where标签,其实用trim也可以表示。当where后紧随AND或者OR的时候,就去除AND或者OR。prefix前缀,perfixOverrides覆盖指定给你的内容

一个测试用例:

<select id="getEmployeeList" parameterType="Employee" resultMap="empmap">
        SELECT
        emp.id,
        emp.name ename,
        emp.age,
        d.name dname,
        a.account
        FROM employee emp LEFT JOIN dept d ON emp.deptId = d.id
        LEFT JOIN admin a ON emp.adminId = a.id
        <trim prefix="where" prefixOverrides="and|or">
            <if test="name!=null &amp; name !=''">
                emp.name  =#{name}
            </if>
            <if test="age!=null &amp; age !='' ">
                and emp.age  =#{age}
            </if>
        </trim>
    </select>

choose (when, otherwise):

在choose标签中when,otherwise就像当与普通java代码中的if else when相当于if otherwise相当于else

解释以下的when,otherwise 当when的test条件成立则执行when标签中的代码否则执行otherwise标签中的代码

代码实例:

 <select id="getEmployeeList" parameterType="Employee" resultMap="empmap">
        SELECT
        emp.id,
        emp.name ename,
        emp.age,
        d.name dname,
        a.account
        FROM employee emp LEFT JOIN dept d ON emp.deptId = d.id
        LEFT JOIN admin a ON emp.adminId = a.id
        <trim prefix="where" prefixOverrides="and|or">
          <choose>
             <when test="name!=null &amp; name!=''">
                 emp.name = #{name}
             </when>
             <otherwise>
                 emp.name = '张三'
             </otherwise>
          </choose>
        </trim>
    </select>

set:

set标签可以动态添加set关键字,可以去掉set语句中最后一个逗号

代码实例:

<update id="updateEmployee" parameterType="Employee">
           update employee
            <set>
              <if test="name!=null">
                  name=#{name},
              </if>
              <if test="age!=null">
                  age=#{age},
              </if>
              <if test="dept.id!=null">
                  deptId=#{dept.id},
              </if>
            </set>
           where id=#{id}
    </update>

也可以用trim:

<update id="updateEmployee" parameterType="Employee">
        update employee
        <trim prefix="set" suffixOverrides=",">
            <if test="name!=null">
                name=#{name},
            </if>
            <if test="age!=null">
                age=#{age},
            </if>
            <if test="dept.id!=null">
                deptId=#{dept.id},
            </if>
        </trim>
        where id=#{id}
    </update>

执行结果:

在这里插入图片描述

Foreach:

主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。

foreach元素的属性主要有:

item:表示集合中每一个元素迭代时起的别名

index:指定一个名字,用于表示在迭代过程中,每次迭代到的位置

collection:属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的。

– 如果传入的是单参数且参数类型是一个 List 的时候,collection 属 性值为 list

– 如果传入的是单参数且参数类型是一个 array 数组的时候, collection 的属性值为 array

open:表示该语句以什么开始

separator:表示在每次进行迭代之间以什么符号作为分隔符

close:close 表示以什么结束

代码实例:

collection=“list” Intger List集合(22,23,24)

 @Test
    public void selectEmlByAge1() {
        SqlSession sqlSession = MybatisUtil.getsqlseeion();
        EmloyeeMapper emloyeeMapper = sqlSession.getMapper(EmloyeeMapper.class);

        List<Integer> list = new ArrayList<>();
        list.add(22);
        list.add(23);
        list.add(24);

        List<Emloyee> emloyeeList = emloyeeMapper.selectEmloyeeByAge1(list);//发送sql
        sqlSession.close();   //关闭

    }
  <select id="selectEmloyeeByAge1" resultType="Emloyee">
        select * from employee where age in
           <foreach collection="list" item="age" open="(" separator="," close=")">
             #{age}
           </foreach>
    </select>

结果:在这里插入图片描述

collection=“list” Integer Array数组 (22,23,24)

@Test
    public void selectEmlByAge2() {
        SqlSession sqlSession = MybatisUtil.getsqlseeion();
        EmloyeeMapper emloyeeMapper = sqlSession.getMapper(EmloyeeMapper.class);
        Integer a[] = new Integer[]{22, 23, 24};

        List<Emloyee> emloyeeList = emloyeeMapper.selectEmloyeeByAge2(a);//发送sql
        sqlSession.close();   //关闭

    }
<select id="selectEmloyeeByAge2" resultType="Emloyee">
        select * from employee where age in
        <foreach collection="array" item="age" open="(" separator="," close=")">
            #{age}
        </foreach>
    </select>

结果:在这里插入图片描述

十.xml文件中的特殊符号处理

在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<> 等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示:

特殊字符 转义字符

< &lt;
> &gt;
" &quot;
’ &apos;
& &amp

如:

在这里插入图片描述

除了可以使用上述转义字符外,还可以使用<![CDATA[]]>来包裹特殊字符。如:

在这里插入图片描述

十一.MyBatis一级二级缓存

为什么使用缓存:

缓存(cache)的作用是为了减去数据库的压力,提高数据库的性能。缓存实现的 原理是从数据库中查询出来的对象在使用完后不要销毁,而是存储在内存(缓存) 中,当再次需要获取该对象时,直接从内存(缓存)中直接获取,不再向数据库 执行 select 语句,从而减少了对数据库的查询次数,因此提高了数据库的性能。 缓存是使用 Map 集合缓存数据的

缓存分类:

一级与二级缓存

一级缓存作用域是同一个SqlSeesion,在同一个SqlSeesion中两次执行相同的的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据不再从数据库查询,从而提高查询效率。当一个SqlSeesion结束后该sqlSeeion中的一级缓存也就不存在了。MyBatis默认开启一级缓存

二级缓存是多个SqlSeesion共享的,其作用域是mapper的同一个namespace,不同的SqlSeesion两次执行相同的namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句第一次执行完毕后会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。MyBatis默认没有开启二级缓存要从setting全局参数中配置开启二级缓存。

​ 一级缓存:

​ MyBatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSeesion而言。所以在参数和 SQL 完全一样 的情况下,我们使用同一个 SqlSession 对象调用一个 Mapper 方法,往往只执 行一次 SQL,因为使用 SelSession 第一次查询后,MyBatis 会将其放在缓存中, 以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下, SqlSession 都会取出当前缓存的数据,而不会再次发送 SQL 到数据库

在这里插入图片描述

一级缓存生命周期:

在这里插入图片描述

a、MyBatis 在开启一个数据库会话时,会 创建一个新的 SqlSession 对象, SqlSession 对象中会有一个新的 Executor 对象。Executor 对象中持有一个新 的 PerpetualCache 对象,如果 SqlSession 调用了 close()方法,会释放掉一级 缓存 PerpetualCache 对象,一级缓存将不可用。

在这里插入图片描述

b、如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象 中的数据,但是该对象仍可使用。

在这里插入图片描述

c、SqlSession 中执行了任何一个 update 操作(update()、delete()、 insert()) ,都会清空 PerpetualCache 对象的数据,但是该对象可以继续使用

在这里插入图片描述
在这里插入图片描述

二级缓存:

二级缓存是 SqlSessionFactory 级别的,根据 mapper 的 namespace 划分区域 的,相同 namespace 的 mapper 查询的数据缓存在同一个区域,如果使用 mapper 代理方法每个 mapper 的 namespace 都不同,此时可以理解为二级缓 存区域是根据 mapper 划分。 每次查询会先从缓存区域查找,如果找不到则从数据库查询,并将查询到数据写 入缓存。Mybatis 内部存储缓存使用一个 HashMap,key 为 hashCode+sqlId+Sql 语句。value 为从查询出来映射生成的 java 对象sqlSession 执行 insert、update、delete 等操作 commit 提交后会清空缓存区 域,防止脏读。二级缓存参考下图所示:

MyBatis 的缓存机制整体设计以及二级缓存的工作模式

在这里插入图片描述

二级缓存的配置:

第一步:启用二级缓存

在 SqlMapperConfig.xml 中启用二级缓存,如下代码所示,当 cacheEnabled 设置为 true 时启用二级缓存,设置为 false 时禁用二级缓存。

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

在这里插入图片描述

第二步:POJO 序列化

将所有的 POJO 类实现序列化接口 Java.io. Serializable。

在这里插入图片描述

第三步:配置映射文件

在 Mapper 映射文件中添加,表示此 mapper 开启二级缓存。 当 SqlSeesion 关闭时,会将数据存入到二级缓存

在这里插入图片描述

设置是SQL语句否开启缓存(select默认就是):

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值