Mybatis框架复习

80 阅读4分钟

1.什么是Mybatis?

Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC--加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高。

Class.forName("com.jdbc.mysql.drvier);
}

2.MyBatis的实现逻辑

在 MyBatis 的初始化过程中,会生成一个 Configuration 全局配置对象,里面包含了所有初始化过程中生成对象。

根据 Configuration 创建一个 SqlSessionFactory 对象,用于创建 SqlSession “会话”。

通过 SqlSession 可以获取到 Mapper 接口对应的动态代理对象,去执行数据库的相关操作。

动态代理对象 执行数据库的操作,由 SqlSession 执行相应的方法,在他的内部调用 Executor 执行器去执行数据库的相关操作。

在 Executor 执行器中,会进行相应的处理,将数据库执行结果返回。

3.一级、二级缓存

一级缓存在 Executor 执行器(SimpleExecutor)中有一个 Cache 对象中,默认就是一个 HashMap 存储缓存数据,执行数据库查询操作前,如果在一级缓存中有对应的缓存数据,则直接返回。

二级缓存在 Executor 执行器(CachingExecutor)中有一个 TransactionalCacheManager 对象中,可以在一定程度上解决的一级缓存中多个 SqlSession 会话可能会导致数据不一致的问题,就是将一个 XML 映射文件中定义的缓存对象放在全局对象中,对于同一个 Mapper 接口都是使用这个 Cache 对象,不管哪个 SqlSession 都是使用该 Cache 对象执行数据库查询操作前,如果在二级缓存中有对应的缓存数据,则直接返回,没有的话则去一级缓存中获取,如果有对应的缓存数据,则直接返回。

4.缓存带来的问题

数据一致性问题 (在实际生产开发中,一级缓存 和 二级缓存 都是要关闭的!!)

image.png

5.## #{} 和 ${} 的区别是什么?

两者在 MyBatis 中都可以作为 SQL 的参数占位符,在处理方式上不同。

#{}:在解析 SQL 的时候会将其替换成 ? 占位符,然后通过 JDBC 的 PreparedStatement 对象添加参数值,这里会进行预编译处理,可以有效地防止 SQL 注入,提高系统的安全性。

${}:在 MyBatis 中带有该占位符的 SQL 片段会被解析成动态 SQL 语句,根据入参直接替换掉这个值,然后执行数据库相关操作,存在 SQL注入 的安全性问题。

6.MyBatis中自定义标签的执行原理

MyBatis 提供了以下几种动态 SQL 的标签:

<if /><choose /><when /><otherwise /><trim /><where /><set /><foreach /><bind />

在 MyBatis 的初始化过程中的解析 SQL 过程中,会将定义的一个 SQL 解析成一个个的 SqlNode 节点对象,当需要执行数据库查询前,需要根据入参对这些 SqlNode 对象进行解析。---> 先解析标签、再语句,最终生成完整的可执行的sql语句。

7.Mybaits的优缺点

(1)优点:

① 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;

② 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。

③ 很好的与各种数据库兼容(因为MyBatis使用JDBC(可以连mysql、oracle....)来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。

④ 能够与Spring很好的集成;

⑤ 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

(2)缺点:

① SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。

② SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

8.mapper如何传递参数?

1)第一种:
//DAO层的函数
Public User selectUser(String name,String area);  
//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<select id="selectUser"resultMap="BaseResultMap">  
    select *  fromuser_user_t   whereuser_name = #{0} anduser_area=#{1}  
</select>2)第二种: 使用 @param 注解:
public interface usermapper {
   user selectuser(@param(“username”) string username,@param(“hashedpassword”) string hashedpassword);
}
然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):
<select id=”selectuser” resulttype=”user”>
         select id, username, hashedpassword
         from some_table
         where username = #{username}
         and hashedpassword = #{hashedpassword}
</select>3)第三种:多个参数封装成map
try{
//映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
//由于我们的参数超过了两个,而方法中只有一个Object参数收集,因此我们使用Map集合来装载我们的参数
Map<String, Object> map = new HashMap();
     map.put("start", start);
     map.put("end", end);
     return sqlSession.selectList("StudentID.pagination", map);
 }catch(Exception e){
     e.printStackTrace();
     sqlSession.rollback();
    throw e; }
finally{
 MybatisUtil.closeSqlSession();
 }

(4) 第4种,通过对象传递(最常用的方式--业务语义清晰)
public class EmailSend {//这是一个对象
    private Integer id;

    private String sourceEmail;

    private String targetEmail;

    private Date createTime;

    private String content;
}
<update id="updateByPrimaryKeySelective" parameterType="com.surwen.base.tool.domain.EmailSend">
    update email_send
    <set>
      <if test="sourceEmail != null">
        source_email = #{sourceEmail,jdbcType=VARCHAR},
      </if>
      <if test="targetEmail != null">
        target_email = #{targetEmail,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="content != null">
        content = #{content,jdbcType=VARCHAR},
      </if>
      <if test="isValid != null">
        is_valid = #{isValid,jdbcType=BIT},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>