Mybatis - 基础知识

Mybatis框架 - 半自动的对象关系映射ORM框架

  1. 资源管理
  2. 封装样板代码
  3. 实现对象关系映射(参数处理和结果集处理)
  4. SQL语句与业务代码解耦,通过xml配置实现sql的统一管理
  5. 动态SQL
  6. 缓存机制和插件机制

Mybatis 架构
mybatis中文官方文档

Mybatis使用案例:

    public static void mapperTest(){
        // 核心对象1: SqlSessionFactoryBuilder:用于读取配置文件并构建出SqlSessionFactory
        // 核心对象2: SqlSessionFactory:用于创建sqlSession的工厂对象,单例
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        // 核心对象3: SqlSession:会话,用于一次sql请求,是线程不安全的。
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            // 核心对象4:mapper代理对象:作用 - 采集调用方法名和参数,映射成mybatis中的statementId和params,在invocationHanlder.invoke()方法中实现sql的调用
            KiqiMapper kiqiMapper = sqlSession.getMapper(KiqiMapper.class);
            
            Kiqi kiqi = new Kiqi(1,"kiqi","123456",18,"kiqi$123");
            kiqiMapper.insert(kiqi);
            System.out.println(kiqi);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

PS:对象关系映射ORM框架(Object Relational Mapping),用于解决对象与关系数据库元数据之间互不匹配的问题。

mybatis-config.xml

<!-- 在SqlSessionFactoryBuilder.build()方法中完成解析,解析后会构成Configuration对象,存在于SqlSessionFactory中 -->
<configuration>
    <!-- 配置文件路径 通过${}符号引用其中的数据 -->
    <properties resource="db.properties"/>

    <!-- 核心配置 -->
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />

        <!-- 1. 开启全局缓存(二级缓存),默认 true -->
        <!-- 一级缓存是基于session的,在同一个session中两次同样的select语句会触发缓存操作,而update类语句会则会清空缓存 -->
        <!-- 二级缓存是基于namespace的,还需在具体的mapper.xml文件中配置缓存才能使对应的namespace应用缓存,与事务(cache是跨事务可见的)相关,只有事务提交后才会设置缓存 -->

        <setting name="cacheEnabled" value="true"/>

        <!-- 2. 延迟加载的全局开关,当开启时,所有关联对象都会延迟加载。默认 false.  1 + N关联查询,使后面的N在需要时(对应属性被使用)才执行 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 与lazyLoadingEnabled一同使用,aggressiveLazyLoading = true代表:对象在被调用任何方法时均触发延迟加载动作 -->
        <setting name="aggressiveLazyLoading" value="true"/>
        <!--  Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
        <!--<setting name="proxyFactory" value="CGLIB" />-->

        <!--设置执行器类型,默认SIMPLE普通执行器,REUSE重用与处理语句,BATCH重用语句且批量执行-->
        <setting name="defaultExecutorType" value="SIMPLE"/>

        <!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
        <!-- <setting name="localCacheScope" value="STATEMENT"/> -->
        <setting name="localCacheScope" value="SESSION"/>
    </settings>

    <!-- 别名,用于简化一些全类名的拼写 - mybatis提供了很多预制的别名,如String -->
    <typeAliases>
        <typeAlias alias="kiqi" type="top.kiqi.mybatis.entity.Kiqi" />
    </typeAliases>

    <!-- 类型转换器,jdbc类型和java类型的相互映射转换,允许自定义,应用时在具体的statement语句或resultMap中设置 -->
    <typeHandlers>
        <typeHandler handler="top.kiqi.mybatis.handler.MyTypeHandler"></typeHandler>
    </typeHandlers>

    <!--四大插件: ①Executor(执行器) ②ParameterHandler(参数处理) ③ResultSetHandler(结果集处理) ④StatementHandler(语句执行) -->
    <plugins>
        <plugin interceptor="top.kiqi.mybatis.intercept.MyPageInterceptor">
            <property name="kiqi" value="123456" />
        </plugin>

        <plugin interceptor="top.kiqi.mybatis.intercept.SQLInterceptor">
        </plugin>
    </plugins>

    <!-- 配置环境 一个environment代表一个数据库 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>    <!-- 事务配置 - 在Spring中,该项配置会被Spring覆盖 -->
            <dataSource type="POOLED">
                <property name="driver" value="${dataSource.driver}"/>
                <property name="url" value="${dataSource.url}"/>
                <property name="username" value="${dataSource.username}"/>
                <property name="password" value="${dataSource.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- Mapper.xml 映射文件配置 -->
    <mappers>
        <mapper resource="mapping/KiqiMapper.xml"/>
        <!--<mapper package="top.kiqi.mybatis.dao"/>-->
        <!--<mapper class="top.kiqi.mybatis.dao.KiqiMapper"/>-->
    </mappers>

</configuration>

mapper.xml

<mapper namespace="top.kiqi.mybatis.dao.KiqiMapper">
  <!-- 1, 只有当namespace中存在cache标签,该namespace才使用二级缓存-->
  <cache type="org.apache.ibatis.cache.impl.PerpetualCache" size="1024" eviction="LRU" flushInterval="120000" readOnly="false"/>
  
  <!-- 2. 重用语句块 -->
  <sql id="Base_Column_List">
    id, username, password, age, addr
  </sql>

  <!-- 3. 结果集,用于结果集映射到java对象-->
  <resultMap id="BaseResultMap" type="top.kiqi.mybatis.entity.Kiqi">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="password" jdbcType="VARCHAR" property="password" />
    <result column="age" jdbcType="INTEGER" property="age" />
    <result column="addr" jdbcType="VARCHAR" property="addr" />
  </resultMap>

  <!-- 4. 增删改查标签 -->
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from kiqi
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from kiqi
    where id = #{id,jdbcType=INTEGER}
  </delete>

  <insert id="insert" useGeneratedKeys="true" parameterType="top.kiqi.mybatis.entity.Kiqi">
    insert into kiqi (username, password,
      age, addr)
    values (#{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},
      #{age,jdbcType=INTEGER}, #{addr,jdbcType=VARCHAR})
  </insert>

  <insert id="insertSelective" parameterType="top.kiqi.mybatis.entity.Kiqi">
    insert into kiqi
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="username != null">
        username,
      </if>
      <if test="password != null">
        password,
      </if>
      <if test="age != null">
        age,
      </if>
      <if test="addr != null">
        addr,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="username != null">
        #{username,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        #{password,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        #{age,jdbcType=INTEGER},
      </if>
      <if test="addr != null">
        #{addr,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.kiqi.mybatis.entity.Kiqi">
    update kiqi
    <set>
      <if test="username != null">
        username = #{username,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        password = #{password,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="addr != null">
        addr = #{addr,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.kiqi.mybatis.entity.Kiqi">
    update kiqi
    set username = #{username,jdbcType=VARCHAR},
      password = #{password,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      addr = #{addr,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

动态Sql - 详见Mybatis官方文档

tips

  1. 逻辑翻页和物理翻页:

    • 逻辑翻页(将数据全部查询到java中,再根据offset丢弃范围之外的数据) - Mybatis RowBounds对象
    • 物理翻页(Sql中采用limit字段实现定向查询) - PageHelper插件,通过拦截StatmentHandler完成SQL语句修改,实现物理翻页
  2. #{}和${}

    • #{}代表预编译,参数部分用?代替,可以防止注入(可缓存,性能高),而${}只是简单的字符串替换,并不能防止sql注入 -> 在能使用#{}的地方均使用#{}
  3. 实现模糊查询:
    ① 字符串拼接:Like %${name}% --- 存在注入风险
    ② CONCAT表达式:Like CONCAT('%',#{name})

  4. 批量更新
    ① foreach动态sql语句
    ② BatchExecutor

posted @ 2021-02-03 17:17  祁奇  阅读(99)  评论(0编辑  收藏  举报