一、Mybatis简介

1.什么是 MyBatis?

        MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
【tips】持久层:JavaEE的三层架构是表现层、业务层、持久层,持久层就是负责将数据保存到数据库的那一层代码。

2.JDBC的不足

(1)硬编码:
        1)注册驱动,获取连接
        2)SQL语句
(2)操作繁琐:
        1)手动设置参数
        2)手动封装结果

3.MyBatis的简化

        MyBatis用配置文件来解决硬编码问题自动完成设置参数(不再一个一个地设置参数)和封装数据的操作。

二、MyBatis核心配置文件

1.核心配置文件的作用?

        MyBatis 的配置文件(官网写为mybatis-config.xml)描述了 MyBatis 行为的设置和属性信息。可以在MyBatis官网(https://mybatis.net.cn/configuration.html)查看。 

2.配置文档的顶层结构


【注意】配置文档标签的前后顺序不能改变
(1)typeAliases:可以为 Java 类型设置一个别名,配置好后不区分大小写。
(2)environments:配置数据库连接环境信息,可以配置多个数据库environment,通过default属性切换不同的environment。
(3)mappers:配置映射文件信息。

三、MyBatis的使用

1.使用MyBatis实现查询所有的操作

(1)创建tb_user表,添加数据;

(2)创建模块,在pom.xml中配置坐标;

        1)mybatis依赖坐标
        2)MySQL驱动坐标
        3)Junit单元测试坐标
        4)logback依赖坐标

(3)编写MyBatis核心配置文件——mybatis-config.xml 

        从 mybatis-config.xml 中构建 SqlSessionFactory将XML配置文件放到类路径下的资源文件(src\main\resources,该配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。
        

(4)编写sql映射(mapper)文件——UserMapper.xml

        1)将SQL语句写到.xml文件里:
<!--
    namespace:名称空间
-->
<mapper namespace="test">
    <!--定义sql语句-->
    <!--
        id:sql语句的唯一标识
        resultType:返回结果的类型
    -->
    <select id="selectAll" resultType="selectAll_Demo.pojo.User">
        select * from tb_user;
    </select>
</mapper>
【tips】①在使用mybatis的时候,会使用到#{}${}这两个符号来为SQL语句传参数,那么这两者有什么区别呢? 
                    a.#{}预编译处理,是占位符;${}是字符串替换,是拼接符
                    b.Mybatis在处理#{}的时候会将sql中的#{}替换成"?"调用PreparedStatement来赋值,可以防止SQL注入;在处理${}的时候就是把${}替换成变量的值,调用Statement来赋值;
            所以在对SQL语句进行参数传递的时候,要用#{参数}
            where条件判断时,对于特殊字符的处理(如小于号<会被当成标签的开始):
                    a.转义字符
                    b.CDATA区:<![CDATA[ 内容 ]]>
                   
        2)sql映射(mapper)文件加载进MyBatis核心配置文件
                   

(5)编码:

        1)定义POJO类;

        2)加载mybatis核心配置文件,获取SqlSessionFactory对象

                固定代码,用就复制:
String resource = "mybatis-config.xml";//mybatish核心配置文件的路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(inputStream);

        3)获取SqlSession对象用来执行sql语句:

                使用SqlSessionFactory的openSession方法获取SqlSession对象(类似JDBC里的Statement对象):
//获取SQLSession对象,用其执行SQL语句
SqlSession ss = ssf.openSession();

//执行SQL语句
//查询所有
List<User> users = ss.selectList("test.selectAll");//传入SQL语句的唯一标识(id),记得带上名称空间(namespace)
【tips】MyBatis事务:在使用openSession方法获取SQLSession对象时,可以通过true和false来设置是否自动提交事务。
//获取SQLSession对象 SqlSession sqlSession = ssf.openSession(true);//自动提交事务

        4)释放SqlSession资源。

2.resultMap映射(★)

        在Mapper接口的配置文件中定义SQL语句时,如果数据库表的列名和实体类的属性名(如brand_name和brandName)不一样,则MyBatis就不能自动封装数据,最终查询到的结果会为null。
        利用resultMap可以将不一样的列名映射为属性名,解决列名和属性名不一样的问题。步骤:
(1)在Mapper接口的配置文件中定义<resultMap>标签
(2)在<select>标签中把resultType属性改为resultMap属性。
<mapper namespace="selectAll_Demo.mapper.UserMapper">

        <!--在Mapper接口的配置文件中定义<resultMap>标签-->
    <!--
        id:resultMap的唯一标识;
        type:映射的类型,支持别名;
    -->
    <resultMap id="userResultMap" type="selectAll_Demo.pojo.User">
            <!--
                id:完成主键字段的映射
                    column:表的列名
                    property:实体类的属性名
                result:完成一般字段的映射
                    column:表的列名
                    property:实体类的属性名
            -->
            <result column="user_name" property="username"/>
    </resultMap>
    
        <!--在<select>标签中把resultType属性改为resultMap属性-->
    <select id="selectAll" resultMap="userResultMap">
        select * from tb_user;
    </select>

</mapper>

【tips】使用注释开发时,在实现类的方法上用注释@ResultMap("userResultMap")代替步骤(2)

3.Mapper代理开发

(1)解决了原生MyBatis使用时的硬编码问题(如图)简化了后期执行SQL语句的操作,可以直接通过sql映射文件里的SQL语句的唯一标识来执行SQL语句


(2)使用Mapper代理的步骤:
        1)定义与sql映射文件同名的Mapper接口,并将sql映射文件Mapper接口的字节码文件(.class)放在同一目录下:

【tips】将二者放在同一目录下时,不建议直接把XML拖过去,因为在Maven的项目结构里是把Java代码和配置文件分开管理的。编译后,resources里的配置文件和Java代码是在同一个classes文件夹里面(如图),所以要把二者放在同一目录下,只需要在resources里新建一个跟mapper存放路径一样的包结构(如图2)(


        2)设置sql配置文件的namespace属性值为Mapper接口全限定名(带路径)
                    这样就将sql映射文件和nmapper联系起来了。
        3)在Mapper接口中定义方法,这些方法是用来使用SQL语句的,方法名就是sql映射文件中SQL语句的id(为了方便调用),并保持参数类型和返回值类型一致:
                (★)方法中参数接收的三种方式
                        1)散装参数:如果方法需要多个参数,需要每个参数前写上@Param("sql语句中占位符名称"),来规定该参数传给SQL语句中的哪个占位符:
                        
                      【tips】数组参数也要@Param。
                        2)实体类封装参数:将需要的参数封装成一个类,类中的属性名要与占位符名称一致:
                        
                        
                        3)Map集合对象参数:将需要的参数和值封装成一个Map集合,集合中的键名要与占位符名称一致:
                        
                        
        4)编码:
                ①加载核心配置文件,获取SqlSessionFactory对象
                ②获取SQLSession对象
                ③获取Mapper接口的代理对象;
                ④调用接口中的方法执行SQL语句。
//获取UserMapper接口的代理对象
UserMapper userMapper = ss.getMapper(UserMapper.class);
//执行SQL语句
List<User> users = userMapper.selectAll();

4.返回添加数据的主键值

        在<insert>标签中添加useGeneratedKeys属性和keyProperty属性:
  • useGeneratedKeys:true(默认为false)表示插入数据时,mybatis可以自动获取从数据库生成的主键
  • keyProperty:主键名。
        

5.动态SQL语句

        动态SQL语句指的是能根据输入条件而动态变化的SQL语句。实现动态SQL语句的标签
(1)if:用来判断参数是否有值,使用test属性进行条件判断,满足test条件才执行if标签内的语句。
        
【注意】test中的条件判断写的是传入的参数,而不是列名。
【tips】在有逻辑运算符连接的多个where条件判断时,如果第一个条件不满足test条件,直接执行带逻辑运算符的第二个条件,这时where直接跟了逻辑运算符,这样就会报错,那么如何解决呢?
                    
                    ①恒等式:在where后加一个恒等式条件(如1 = 1):
                            
                    ②用<where>标签代替where关键字
                            
(2)choose (when, otherwise):可以从多个条件中选择一个条件进行查询,类似switch语句,其中when类似case,otherwise类似default
        
(3)trim (where, set):<trim>标签一般用于去除SQL语句中多余的and关键字、逗号或者给SQL语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于动态插入、更新、删除或者条件查询等操作。
(4)foreach:用于遍历数组
            【各属性名及含义见6.(2)】

6.批量删除(★)

(1)接口方法的参数:id数组
(2)sql映射文件中SQL语句的编写:
<!--批量删除-->
<delete id="deleteByIds">
    delete
    from tb_brand
    where id in
    <!--
        collection:要遍历的集合名
        item:集合中每一个元素进行遍历时的别名
        separator:表示在每次进行遍历之间以什么符号作为分隔符
        open/close:表示该语句以什么开始/以什么结束
    -->
    <foreach collection="array" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</delete>
【tips】★★在MyBatis中会将数组参数封装成一个Map集合,默认键名为array,array对应的值就是被封装的数组。所以在使用foreach遍历数组时,collection属性要写数组对应的键即collection=array
【tips】如果想自定义Map中的键名,可以在定义Mapper接口方法时,用@Param("新键名")注解来重命名键名,然后collection属性就可以写"新键名"了
//批量删除
void deleteByIds(@Param("ids") int[] ids);
<!--批量删除-->
<delete id="deleteByIds">
    delete
    from tb_brand
    where id in
        <!--collection="新键名"-->      <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</delete>

7.MyBatis参数传递

        MyBatis底层对于不同类型参数的封装方式不同:
(1)单个参数:
        1)pojo类型:直接使用,实体类的属性名参数占位符的名称一致。
        2)Map集合:直接使用,键名参数占位符的名称一致。
        3)Collection集合:封装成Map集合
map.put("collection",collection集合);
map.put("arg0",collection集合);
        4)List集合:封装成Map集合
map.put("collection",list集合);
map.put("list",list集合);
map.put("arg0",list集合);
        5)Array:封装成Map集合
map.put("array",数组);
map.put("arg0",数组);
        6)其他类型,如int:直接使用。
(2)多个参数:
          封装为Map集合
map.put("arg0",参数值1);
map.put("param1",参数值1);
map.put("arg1",参数值2);
map.put("param2",参数值2);
【tips】被封装成Map集合的参数,一般都用@Param("新键名")注解来修改Map集合中默认的键名,并用新键名来获取值。

8.注解开发

(1)在Mapper接口中定义方法时,用注解来写SQL语句:
        
【tips】@ResultMap("resultMap_id")可以解决SQL语句字段名与pojo类属性名不一致的问题。
(2)注解开发适用于简单的SQL语句,配置文件开发适用于复杂的SQL语句。