1. MyBatis基本工作原理介绍 

[MyBatis的基本工作原理就是]:

先封装SQL,接着调用JDBC操作数据库,最后把数据库返回的表结果封装成Java类。

         [作用]: Mybatis框架解决了数据库编程相关的问题,主要是简化了数据库编程。 当使用Mybatis框架实现数据库编程时,只需要:     - 定义数据操作功能的抽象方法(此抽象方法必须在接口中)     - 配置以上抽象方法映射的SQL语句      [特殊]     计算机的基本工作就是存储和计算,而MyBatis是存储领域的利器。

2. MyBatis的核心流程介绍

[]简写步骤]

1.mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory

2.后通过SqlSessionFactory的实例直接开启一个SqlSession(创建会话对象)

3.通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,

4.关闭SqlSession。

[详写步骤] 

  • /**上面中流程就是MyBatis内部核心流程,每一步流程的详细说明如下文所述:*/(最下方流程图)
  • (1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。
  • (2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
  • (3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。
  • (4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。
  • /**通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交*/
  • (5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。
  • (6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。
  • (7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。
  • (8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。

MyBatis四大核心+JDBC有四个核心对象

JDBC有四个核心对象:
(1)DriverManager,用于注册数据库连接
(2)Connection,与数据库连接对象
(3)Statement/PrepareStatement,操作数据库SQL语句的对象
(4)ResultSet,结果集或一张虚拟表

MyBatis也有四大核心对象:
(1)SqlSession对象,该对象中包含了执行SQL语句的所有方法【1】。类似于JDBC里面的Connection 【2】。
(2)Executor接口,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。类似于JDBC里面的Statement/PrepareStatement。
(3)MappedStatement对象,该对象是对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息。
(4)ResultHandler对象,用于对返回的结果进行处理,最终得到自己想要的数据格式或类型。可以自定义返回

 [图解]

Javamybatis按批处理数据 mybatis批处理原理_SQL

 3.MyBatis常用注解

@MapperScan :后跟路径指向mapper包,对mapper包进行扫描, ,与@Configuration(配置类连用)连用,作用是可以不用在每个接口上都加@Mapper注解了

@Mapper        :在接口类上添加了@Mapper @Repository @Param :参数标签 @Insert @Delete @Update @Select(不使用 .xml文件 写SQL语句时使用) (具体用法放在mapper接口中的抽象方法上使用)  

4.常用关键字

/**id="insert"  id等于的是mapper中抽象方法的方法名*/
<insert id="insert" useGeneratedKeys="true" keyProperty="id"></insert> //配置自增id写法
    
/**封装字段*/    
<include refid="DetailQueryFields" />

<sql id="DetailQueryFields">
        <if test="true">
        //此处存放字段名用,隔开写多个   
        </if>
</sql>

ResultMap,ResultType 区别

/**ResultMap,ResultType 区别*/ 

基本映射 :(resultType)使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。(数据库,实体,查询字段,这些全部都得一一对应)高级映射 :(resultMap) 如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。(高级映射,字段名称可以不一致,通过映射来实现
    
resultType和resultMap功能类似 ,都是返回对象信息 ,但是resultMap要更强大一些 ,可自定义。
因为resultMap要配置一下,表和类的一一对应关系,所以说就算你的字段名和你的实体类的属性名不一样也没关系,都会给你映射出来
------------------------------------------------  
<select id="count" resultType="int"> </select>
<select id="count" resultType="cn.tedu.csmall.server.pojo.vo.AlbumListItemVO"> </select>
    
<select id="getById" resultMap="DetailResultMap"></select>     
<resultMap id="ListItemResultMap" type="cn.tedu.csmall.server.pojo.vo.AlbumListItemVO">
        <id column="id" property="id"/>
            <result column="product_count" property="productCount" />
</resultMap>  
-----------------------------------------------------
            
/**当外部传入List时怎么处理  遍历集合*/            
<foreach collection="array" item="id" separator=",">#{id}</foreach>

[此例子为得到自动编号的ID值]

另外,在插入数据时,还可以配置,得到自动编号的ID值,具体做法是在<insert>节点上添加配置: <insert id="insert" useGeneratedKeys="true" keyProperty="id">     暂不关心此处的SQL语句 </insert>

6.关于此文件的配置(两个地方)

/**关于.xml此文件的内部配置:*/

1.根节名必须是<mapper>
2.根节点必须配置namespace属性,取值为对应的接口的全限定名
    (例子:<mapper namespace="cn.tedu.csmall.server.mapper.AlbumMapper">)
3.在根节点内部,根据需要执行的SQL语句的类型不同,使用<insert>、<delete>、<update>、<select>节点
4.在<insert id="">等节点上,必须配置id属性,取值为抽象方法的名称(不包含括号及参数)
5.在<insert><insert/>等节点内部,配置SQL语句,SQL语句不需要使用分号结束


/**在application.properties类中的数据配置*/
1.[此例子为配置.xml文件所在位置]
需要补充一个配置,用于告诉Mybatis框架.xml文件的位置!在application.properties中添加:
mybatis.mapper-locations=classpath:mapper/*.xml     
(/**的意思是所有文件夹及里面的子文件夹
 /*是所有文件夹,不含子文件夹
 /是web项目的根目录)

2.[配置连接数据库的参数] 
//数据库端口号+数据库名字+统一编码+utf-8编码+时区
spring.datasource.url=jdbc:mysql://localhost:3306/mall_pms?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
//接通数据库时的用户名+密码
spring.datasource.username=root
spring.datasource.password=root                  */      

特殊3.[Spring Boot在application.properties类中配置,服务端口(默认8080)]
server.port=8080

3.[此例子为得到自动编号的ID值]
另外,在插入数据时,还可以配置,得到自动编号的ID值,具体做法是在<insert>节点上添加配置:
<!-- int insert(Brand brand); -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    暂不关心此处的SQL语句
</insert>

7. Mybatis实现动态SQL的修改数据(if,null)(<foreach遍历集合 >)

/**Mybatis实现动态SQL的修改数据*/

1). 在动态SQL机制中,可以使用`<if>`标签,可用于对某参数值进行判断,从而生成不同的SQL语句片段,常用于设计更新数据的操作。

目标:使用1个方法,实现多种不同的数据更新(想更新哪些字段就更新哪些字段,不想更新的字段值将保持不变)

需要执行的SQL语句大致是:
update pms_brand set name=?, pinyin=?, logo=? where id=?

2). 注意:以上SQL语句的修改的字段列表应该不是固定的,应该根据传入的参数值来决定 , 
先在BrandMapper接口中添加抽象方法:int updateById(Brand brand);

然后,在BrandMapper.xml中进行配置:
<!-- int updateById(Brand brand); -->
<update id="updateById">
	UPDATE
    	pms_brand
    <set>
    	<if test="name != null">
            name=#{name},
    	</if>
        <if test="pinyin != null">
        	pinyin=#{pinyin},
	    </if>
    	<if test="logo != null">
        	logo=#{logo},
	    </if>
    </set>
    WHERE
    	id=#{id}
</update>

1). 需要注意的是,在Mybatis的动态SQL中,<if>并没有对应的<else>,如果一定要实现类似Java中的if...else效果,需要使用<choose>标签,其基本格式是:
<choose>
	<when test="条件">
    	满足条件时的SQL片段
    </when>
    <otherwise>
    	不满足条件时的SQL片段
    </otherwise>
</choose>

2). 或者,也可以使用2个条件完全相反的<if>标签来实现类似效果(但是执行效率偏低),例如:
<if test="pinyin != null">
    某代码片段
</if>
<if test="pinyin == null">
    某代码片段
</if>

遍历传入的集合数据的id,根据id挨个删除每条数据

<foreach collection="array" item="id" separator=",">
    #{id}
</foreach> 
    
    例子: 遍历传入的集合数据的id,根据id挨个删除每条数据
    <delete id="deleteByIds">
        DELETE
        FROM
            pms_brand
        WHERE
            id IN (
                <foreach collection="array" item="id" separator=",">
                    #{id}
                </foreach>
            )
    </delete>