MyBatis详解

1. MyBatis的优点

  • 不屏蔽SQL,意味着可以更为精确地定位SQL语句,可以对其进行优化和改造,这有利于互联网系统性能的提高,符合互联网需要性能优化的特点
  • 提供强大的,灵活的映射机制,方便Java开发者使用,提供动态的SQL功能,允许我们根据不同条件组装SQL,这个功能远比其他工具或者Java编码的可读性和可靠性高得多,满足各种应用系统的同时,也满足了需求经常变化的互联网应用的要求
  • 在MyBatis中,提供了使用Mapper的接口编程,只要一个接口和一个xml就能创建映射器,进一步简化我们的操作,使得很多的框架API在MyBatis中消失,开发者能更加集中业务逻辑

2. MyBatis四个核心组件

  1. SqlSessionFactoryBuilder(构造器)

    它会根据配置或者代码来生成SqlSessionFactory,采用的是分布构建的Builder模式

  2. SqlSessionFactory(工厂接口)

    依靠它来生成SqlSession,使用的是工厂模式

  3. SqlSession(会话)

    一个既可以发送SQL执行返回结果,也可以获取Mapper的接口,在现有的技术中,一般我们会让其在业务逻辑代码中"消失",而使用的是MyBatis提供的SQL Mapper接口编程技术,它能够提高代码的可读性和可维护性

  4. SQL Mapper(映射器)

    MyBatis新设计存在的组件,它是由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则,它负责发送SQL去执行,并返回结果

2.1 SqlSessionFactory

​ 在MyBatis中生成SqlSessionFactory有两种方式:

  • 读取配置的XML方式★★★★
  • 通过Java代码的形式(不推荐)
通过XML构建SqlSessionFactory

​ 在MyBatis里面的XML:

  • 基础配置文件

    配置最基本的上下文参数和运行环境

    命名为mybatis-config.xml,放在工程路径下

  • 映射文件

    配置映射关系,SQL,参数等信息

2.2 SqlSession

​ 在MyBatis中,SqlSession是核心接口,在MyBatis中有两个实现类

  • DefaultSqlSession 单线程

  • SqlSessionManager 多线程

    SqlSession的作用就类似于JDBC中Connection对象,代表一个连接资源的启用

SqlSession的作用
  • 获取Mapper接口
  • 发送SQL给数据库
  • 控制数据库事务
//SqlSession事务控制的伪代码

//定义SqlSession
SqlSession sqlSession = null;
try{
    //打开SqlSession会话
    sqlSession = SqlSessionFactory.openSession();
    //some code....
    sqlSession.commit();  //提交事务
}catch(Exception e){
    sqlSession.rollback();  //回滚事务
}finally{
    //在finally语句中确保资源被顺利关闭
    if(sqlSession != null){
        sqlSession.close();
    }
}

2.3 映射器

映射器是MyBatis中最重要,最复杂的组件,它是由一个接口和XML文件(或注解)组成

映射器可以配置
  • 描述映射规则
  • 提供SQL语句,并可以配置SQL的参数类型,返回类型,缓存刷新等信息
  • 配置缓存
  • 提供动态SQL
实现映射器的两种方式
  • XML方式
  • 注解方式

在实现映射器之前需要先定义POJO

映射器的主要作用就是将SQL查询到的结果映射为一个POJO,或者将POJO的数据插入到数据库中,并定义一些关于缓存的重要内容

开发的只是一个接口,而不是一个实现类,接口实际上不能直接运行,但是MyBatis运用了动态代理的技术是接口能够运行起来,入门阶段只需要了解MyBatis会为这个接口生成一个动态代理对象,代理对象回去处理相关逻辑

利用XML实现映射器★★★★

利用XML去实现映射器分为两部分

  • 接口
  • XML
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
    mapper:核心根标签
    namespace属性:名称空间
-->
<mapper namespace="studentMapper">

    <select id="findAll" resultType="student">
        select * from student;
    </select>
</mapper>

注意: 这里并没有配置SQL执行后和student的对应关系,它是通过自动映射的功能,MyBatis在默认情况下提供自动映射

只要SQL返回的列名column能够和POJO的属性名对应起来

SqlSession发送SQL
 @Test
    public void findById(){
        SqlSession sqlSession = factory.openSession();
        Student student = sqlSession.selectOne("studentMapper.findById",1);
        System.out.println("student = " + student);
        sqlSession.close();
    }
//这是MyBatis沿用iBatis所留下来的方式
用Mapper接口发送SQL★★★★
@Test
    public void findById(){
        SqlSession sqlSession = factory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.findById(1);
        System.out.println("student = " + student);
        sqlSession.close();
    }
//利用Mapper 发送SQL
//SqlSession的getMapper方法获取一个Mapper接口,就可以调用它的方法
//因为XML文件和接口注解定义的SQL都可以通过"全限定名+方法名"查找,
//所以MyBatis会启用相应的SQL进行运行,并返回结果
对比两种发送SQL方式
  • 使用Mapper接口编程可以消除SqlSession带来的功能性代码,提高可读性,完全面向对象的语言,更能提高业务的逻辑
  • 使用Mapper接口编程,IDE会提示错误和校验,sqlSession.selectOne()这种只有在运行中才能知道是否产生错误

3. MyBatis的配置

//此处省略一万字

引入映射器

映射器是MyBatis最复杂的最核心的组件

映射器定义命名空间(namespace)的方法,命名空间对应的是一个接口的全路径,而不是实现类

<!--定义Mapper映射规则和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.blue_ocean.mapper.UserMapper">
<select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
  1. 用文件路径引入映射器

    <mappers>
            <mapper resource="com.blue_ocean.mapper.UserMapper.xml"/>
    </mappers>
    
  2. 用包名引入映射器

    <mappers>
            <package name="com.blue_ocean.mapper"/>
    </mappers>
    
  3. 用类注册引入映射器

    <mappers>
            <mapper class="com.blue_ocean.mapper.UserMapper"/>
    </mappers>
    
  4. 用userMapper.xml引入映射器

    <mappers>
            <mapper url="com.blue_ocean.mapper.UserMapper.xml"/>
    </mappers>
    

4. 映射器Mapper

映射器是MyBatis最复杂的最核心的组件

在映射器中我们可以配置参数,各类的SQL语句,存储过程,缓存,级联等复杂的内容,并且通过简易的映射规则映射到指定的POJO或许和其他对象上,映射器能有效地消除JDBC底层的代码

在MyBatis应用程序开发,映射器的开发工作量占绝大部分,

XML和注解:

  • 面对复杂性:SQL会显得无力,尤其是长SQL
  • 注解的可读性比较差
  • 在功能上注解丢失了XML上下文相互引用的功能,基于实用情况,XML更好用

概述

映射器的配置元素

元素名称 描述 备注
select 查询语句,最常用,最复杂的元素之一 可以自定义参数,返回结果集等
insert 插入语句 执行后返回一个整数,代表插入的条数
update 更新语句 执行后返回一个整数,代表更新的条数
delete 删除语句 执行后返回一个整数,代表删除的条数
sql 定义一部分SQL,然后在别的地方引用 例如:一个表列名,一次定义,多次使用
resultMap 用来描述从数据库结果集中来加载对象,它是最复杂,最强大的元素 它将提供映射规则
cache 给定命名空间的缓存配置 ----

select元素

元素 说明 备注(仅列出常用的)
id id和Mapper的命名空间组合一起是唯一的,供MyBatis调用 不唯一,就会抛出异常
parameterType 可以给出类的全命名,也可以给出别名,但是别名必须是MyBatis内部的 可以选择JavaBean,Map等简单的参数类型传递给SQL
resultType - 定义类的全路径,在允许自动匹配的情况下,结果集将通过JavaBean的规范映射;- 或定义为int,double,float,map等参数 - 也可以使用别名,但是要符合命名规范, 不能和resultMap同时使用
resultMap 它是映射集的引用,将执行强大的映射机制,我们可以使用resultType和resultMap其中一个,resultMap能提供自定义映射规则的机会O MyBatis最复杂的元素,可以配置映射规则,级联,typeHandler

insert元素

元素 说明 备注
id SQL编号,用于识别这条SQL 命名空间+id+databaseId唯一
parameterType 参数类型,同select元素 和select一样,可以是多个参数
useGeneratedKeys 是否启用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键 默认值为false
keyProperty MyBatis会通过getGeneratedKeys的返回值,或者通过insert语句的selectKey子元素设置它的键值,如果是复合主键,要把每一个名称用逗号隔开 (仅对insert和update有用)唯一的标记一个属性,默认值unset
keyColumn 通过生成的键值设置表中的列名,这个设置仅在某些数据库中式必须的,当主键列不是表中的第一列时需要设置,如果是复合主键,需要把每一个名称用逗号(,)隔开 (仅对insert和update有用)唯一的标记一个属性,不能和keyProperty连用
主键回填
<insert id="add" parameterType="student">
        insert into student(name,age) values (#{name},#{age});
</insert>
<!--没有插入id列,因为MySQL中表格采用了主键自增,数据库会生成相对应的主键,
有时候我们可能还需要用到这个主键,此时利用useGeneratedKeys属性,值设为true,
此时需要同时用keyProperty和keyColumn,告诉系统把生成的主键当在哪个属性-->

resultMap元素

<resultMap id="StudentMapper" type="Student">
        <!--配置学生基本信息-->
        <id column="sid" property="sid"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>

        <!--配置学生所属班级信息  private Classes classes;-->
        <association property="classes" javaType="Classes">
            <id column="cid" property="cid"/>
            <result column="cname" property="cname"/>
        </association>

</resultMap>
resultMap元素的属性
  • id代表这个resultMap的标识
  • type代表需要映射的POJO
    • 这里可以使用MyBatis定义好的类的别名
    • 也可以使用自定义的类的全限定类名
      • property :代表POJO的属性名称
      • column:代表数据库SQL的列名

5. 级联

级联简介

MyBatis的级联分为3种

  • 鉴别器(discriminstor):根据某些条件决定采用具体实现类基连的方案

  • 一对一(association)

  • 一对多(collection)

    • 每个级联元素中的属性id的配置和POJO的实体配置中的id一一对应形成级联,这是级联关键所在

    • 在级联的元素中association是通过javaType的定义去声明实体映射的

    • collection 中是使用ofType进行声明的

级联的N+1问题

问题描述

☆ 当级联成功后,有时候引发性能问题,比如一个简单的查询就关联很多无关数据

★ 假设现在有N个关联关系完成了级联,那么要是在加入一个关联关系,就变成了N+1级联,所有的级联SQL都会被执行

在高性能的互联网系统中是不允许的

提出解决办法:延迟加载

延迟加载

MyBatis支持延迟加载(需要就加载,不需要不加载),这些不常用的级联数据可以采用延迟加载

配置项 作用 配置说明 默认值
lazyLoadingEnabledy 延迟加载的全局开关,所有的关联对象都会延迟加载,在特定的关联关系中,可通过设置fetchType属性来覆盖该项的开关状态 true|false false
aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载的属性的对象完整加载;反之,这种属性按需加载 true|false 3.4.1后为false
 <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="true"/>
 </settings>

<!-- 这两个属性是配置全局变量,也可以配置局部变量-->
<!-- 在association和collection中 配置fetchType-->
<!-- eager 获得当前POJO后立即加载对应的数据 -->
<!-- lazy 获得当前POJO后延迟加载对应的数据 -->

6. 动态SQL

概述

MyBatis提供对SQL语句动态的组装能力,使用XML元素,大量的判断都可以在MyBatis的映射XML里面配置,体现了MyBatis的灵活,高度可配置性和维护性

动态SQL的元素

元素 作用 备注
if 判断语句 单条件分支判断
choose(when,otherwise) 相当于Java中的switch和case语句 多条件分支判断
trim(where,set) 辅助元素,用于处理特定的SQL拼装问题 用于处理SQL拼装的问题
foreach 循环语句 在in语句等列举条件常用
<!-- 利用test的属性去判断字符串-->

<select id="findByCondition" parameterType="Student" resultType="Student">
        select * from student
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
        </where>
    </select>

<select id="findByIdCondition" parameterType="int" resultType="Student">
        Select * from student
        <foreach collection="list" open="where id IN (" close=")" item="id" separator=",">
            #{id}
        </foreach>
</select>

posted @ 2021-04-10 23:40  蔚蓝的海洋  阅读(431)  评论(0编辑  收藏  举报