Mybatis

560 阅读3分钟

Mybatis 基础知识

Mybatis 的执行过程

    1. 加载 mybatis 配置文件,得到一个输入流
    1. 通过 SqlSessionFactoryBuilder().build() 加载输入流, 从而获得 SqlSessionFactory, SqlSessionFactory 是单例的;相当于数据库连接池
    1. 通过 SqlSessionFactory.openSession(), 获取 SqlSession
    1. SqlSession 执行 xxMapper.xml
    1. sqlSession.close();
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");
// 提交事务
sqlSession.commit();
// 关闭连接
sqlSession.close();

configuration 配置文件中的几个重要属性

typeAliases

bean 的别名;
有两种方式:
1. 
</select>
    <select id="selById2" resultType="user" >
  		select * from people where id = #{id}
</select>
在 configuration.xml 中
 <typeAliases>
        <typeAlias type="com.xx.User" alias="user"/>
 </typeAliases>
 或者
 <typeAliases>
        <!--使用包扫描的方式-->
        <package name="com.xx"/>
 </typeAliases>
 2.
 @Alias("user")
 public class User{...}

properties

使用方式有三种:

1: 
在properties 属性中增加 property 属性,用来设置一些属性的name, value
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
2: 
引入外部配置类
<properties resource="db.properties" />
3:
Java 代码中使用,获取配置文件中的属性

String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(is);
String userName = properties.getProperty("db.username");
String pwd = properties.getProperty("db.pwd");
properties.setProperty("db.username", CyperTool.decodeByBase64(userName));

settings

<settings>
		<setting name="cacheEnabled" value="true" />
		<setting name="useGeneratedKeys" value="true" />
		<setting name="defaultExecutorType" value="REUSE" />
		<setting name="logImpl" value="STDOUT_LOGGING" /> // 
</settings>
  • cacheEnabled // 全局开启或者关闭缓存, true/false
  • lazyLoadingEnabled // 全局懒加载开关
  • logimpl // 指定 mybatis 日志的具体实现,未指定时将自动查找

xxMapper.xml 重要的属性

ResultMap 结果集映射

设置数据库字段和bean 属性映射

<resultMap id="BaseResultMap" type="com.xx.User">
    <id column="ID" jdbcType="BIGINT" property="id" />
    <result column="SKU_NAME" jdbcType="VARCHAR" property="skuName" />
    <result column="CATEGORY_ID" jdbcType="BIGINT" property="categoryId" />
</resultMap> 

<select id="getUserList" resultMap="BaseResultMap" parameterType="User">

Mybatis 分页

1. limit
2. 利用 RowBounds

注解

1. 绑定接口
public interface UserMapper {
   @Select("select * from user")
    List<User> findAll();
}

多个参数 @Param

只能在元素参数上使用

Public User selectUser(@param(“userName”)String name,@param(“userArea”)String area); 

<select id=" selectUser" resultMap="BaseResultMap"> 
   select  *  from user_user_t   where user_name = #{userNamejdbcType=VARCHAR} and user_area=#{userArea,jdbcType=VARCHAR} 
</select>

${} 和 #{} 区别

#{} 是预编译的,防止SQL注入

association 、collection

<resultMap type="Student" id="studentResultMap">
 <id column="id" property="id" /> 
 <result column="name" property="name" /> 
 <result column="gender" property="gender" />
 <result column="major" property="major" /> 
 <result column="grade" property="grade"/> 

  // 集合 - 一对多
  <collection property="emps" ofType="com.mybatis.bean.Employee">
      <id column="eid" property="id"/>
      <result column="last_name" property="lastName"/>
      <result column="email" property="email"/>
      <result column="gender" property="gender"/>
  </collection>


   // 对象 - 多对一
   <association property="supervisor" javaType="Teacher"> 
    <id property="id" column="t_id"/> 
    <result property="name" column="t_name"/> 
    <result property="gender" column="t_gender"/> 
    <result property="researchArea" column="research_area"/> 
   </association> 
 
</resultMap> 

#
ofType : 用来指定映射到 List
JavaType : 指定实体类中属性的类型

动态 SQL

根据不同的条件生成不同的 SQL, Mybatis 的动态SQL 基于 OGNL 表达式

if
<select id="dynamicIfTest" parameterType="Blog" resultType="Blog">
        select * from t_blog where 1 = 1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="content != null">
            and content = #{content}
        </if>
        <if test="owner != null">
            and owner = #{owner}
        </if>
    </select>
choose
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
        select * from t_blog where 1 = 1 
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="content != null">
                and content = #{content}
            </when>
            <otherwise>
                and owner = "owner1"
            </otherwise>
        </choose>
    </select>
    
trim
<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
        select * from t_blog 
        <trim prefix="where" prefixOverrides="and |or">
            <if test="title != null">
                title = #{title}
            </if>
            <if test="content != null">
                and content = #{content}
            </if>
            <if test="owner != null">
                or owner = #{owner}
            </if>
        </trim>
    </select>
where

<select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
        select * from t_blog 
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="content != null">
                and content = #{content}
            </if>
            <if test="owner != null">
                and owner = #{owner}
            </if>
        </where>
    </select>

set
 <update id="dynamicSetTest" parameterType="Blog">
        update t_blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="content != null">
                content = #{content},
            </if>
            <if test="owner != null">
                owner = #{owner}
            </if>
        </set>
        where id = #{id}
    </update>

foreach

对集合进行遍历

<select id="dynamicForeachTest" resultType="Blog">
        select * from t_blog where id in
        <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>
    

动态SQL include

引用SQL片段

<include refid = "" />

MyBatis 缓存

经常查询的数据存在内存中的临时数据,为了减少与数据库的交互 两级缓存。默认只开启一级缓存(sqlsession 级别的,也成为本地缓存), 二级缓存需要手动开启,它是基于nameSpace 级别的缓存, Mybatis 提供了 Cache 接口,可以通过它来自定义二级缓存

一级缓存

也叫本地缓存,与数据库同一次查询期间(SqlSession 开启到关闭期间)缓存到本地缓存,下次查询相同数据,直接获取

缓存失效的情况

  • 查询不同的东西
  • 增删改
  • 关闭清楚缓存, sqlSession.clearCache()

二级缓存

<!--开启二级缓存  -->
<settings>    
<setting name="cacheEnabled" value="true"/>
</settings>

其次在 UserMapper.xml 文件中开启缓存
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

Mybatis 的缓存机制原理

第一次查询先看二级缓存,再看一级缓存,都没有走数据库,放入一级缓存;

使用自定义缓存

TODO.....

常用版本

3.x

Spring 整合 Mybatis

步骤:

    1. 导入相关 jar 包
      • junit
    • mybatis
    • mysql 数据库
    • Spring 相关
    • aop 织入
    • mybatis-spring
    1. 编写配置文件

xxMapper.xml

1. namespace - 命名空间,绑定一个对应的 Mapper 接口,名字一致
2. <select id ="xx" ....> - id 对应 Mapper 接口的方法名
3. <select id ="xx" resultType = "com.xx..."> - resultType 返回值
4. parameType - 参数类型
5. #{id} - 占位符获取参数
6. <insert parameType = "com.xx" 

面试题

SqlSession 和 Mapper 是如何执行的?

通过mapeer.xml 的 namespace 来唯一定位

Mybatis 默认连接是什么?

JDBC , 默认连接池方式