o(* ̄︶ ̄*)o

  博客园  :: 首页  ::  :: 联系 :: 订阅 订阅  :: 管理

MyBatis总结

1.什么是MyBatis

  是一个ORM对象关系映射框架,应用持久层框架,内部封装了JDBC.

  可以使用XML、或注解来配置和映射数据。

  所写的SQL语句,依赖数据库,不好更换数据库;字段多,联表查询时,不好维护,考验SQL编写能力。

  与同类产品Hibernate相比,无法根据对象模型(对象与库表关系)直接获取,配置简单,没提供日志、缓存,HQL操作数据库等特性,性能相对好

不支持多种数据库,SQL语句优化相对容易,SQL语句编写工作量大些,适合需求变化频繁,项目大的。

2.MyBatis使用过程?工作原理?生命周期?

  • SqlSessionFatoryBuilder:加载配置文件(数据库配置【测试/生产】,执行Sql映射配置),并生成SqlSessionFatory
  • SqlSessionFatory : 创建SqlSession,类似数据库连接池,单例模式;
  • SqlSession :  指定【Sql映射配置文件】中  ID,并传入参数,执行SQL;
  • Mapper : 映射器(【Sql映射配置文件】),绑定映射语句接口,生命周期由SqlSession 内部控制
  • 提交事务或回滚 : commit 、rollback
  • 关闭Session

  SqlSession 不是线程安全的,不能共享,生命周期是一次请求。

        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
            //初始化错误时,通过抛出异常ExceptionInInitializerError通知调用者
            throw new ExceptionInInitializerError(e);
        }

       /**********************    分割线     *******************/
       /************       以下部分在功能中重复使用         ***********/
        //选择默认执行器(SimpleExecutor, ReuseExecutor,BatchExecutor)
       SqlSession sqlSession  = sqlSessionFactory.openSession();

        //选择执行哪个SQL,并填入相应条件参数
       //数据表类中的字段需要覆盖配置中返回的字段
        数据表类 A = sqlSession.selectOne("映射表的空间名.id名”,  参数(基础类型,Map, 自定义类型)
    
      //若新增,删除,更新,需要执行如下
        sqlSession.commit();

    //打开会话,必须关闭
    sqlSession.close();

  

3.MyBatis口诀

  • 三层构架:API接口层(增删改查)、数据处理层(处理映射文件,查找/解析/执行/结果映射)、基础支撑层(配置加载,缓存处理,连接管理等)
  • 二级缓存:一级缓存(各SqlSession相互隔离,Session flush或close时,缓存释放,默认一级缓存);二级缓存
  • 四个组件组成:SqlSessionFatoryBuilder 、SqlSessionFatory  、SqlSession 、Mapper
  • 会话执行四步骤:执行器Executor 、参数处理器ParameterHandler 、数据库会话处理器StatementHandler 、结果集处理器ResultSetHandler
  • 两个配置文件:基础配置文件和映射配置文件

  3.1    执行器Executor(SIMPLE普通执行器,REUSE重用【预处理语句】,BATCH重用语句并批量更新。)

    SqlSession(ExecutorType execType);

    提供了查询、更新、及事务方法。

  3.2  二级缓存

       跟一级缓存一样,采用了PerpetualCahe的HashMap存储

   作用域:Mapper(namespace),可多个SqlSession共享,自定义数据源(Ehcache)

   打开:默认不打开

     使用:开启,需要映射文件配置,要实现Serializable序列化接口(保存对象状态)

4. 获取Mapper接口原理

  Maper ->   MapperProxyFactory -> MapperProxy -> MapperMethod -> execute

  Mapper映射,通过cglib动态代理(类名.class ),按以上步骤进行获取。

5.配置SQL中定义参数用于条件赋值:#{参数名} 或 ${参数名}

  #{} 会进行预编译处理,替换?号,参数以字符串形式传入,通过预编译(PreparedStatement)的set方法赋值。

  ${} 直接替换,有SQL注入风险,且参数若是字符串,替换后系统不会给该字段添加引号。例如:where prod_name=产品名;  //语句执行失败。

  风险:期望查询 select * from prod_info where prod_id = ${参数id}

  被非法替换:select * from prod_info where prod_id = '参数id' and prod_name = '参数名称';    //从and开始都是外部传入,与预期查询结果不符。 

6.插件使用,拦截器

  {...}

7.给Sql传参

  顺序传参 : 字段1 = #{0}  and 字段2 =  #{1}

  注解:  public  返回类型 方法(@Param("字段名1") String 字段名1,@Param("字段名2") String 字段名2 )

      字段1 = #{字段名1}  and 字段2 =  #{字段名2}

  Map传参 /自定义类传参:Map根据的Key,类就成员变量无关私有或公有 

8.模糊查询

concat('%', #{参数名}, '%')

XML中转义字符&emsp

 

9.结果关联查询

 

10.association关联对象、Collection关联集合查询支持延迟加载

需要配置lazyLoadingEnabled=true|false;

 

11.基础配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
 
    <!--启用Pagehelper分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--设置数据库类型-->
            <property name="helperDialect" value="mysql"/>
            <!--分页合理化-->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
    
    <!--设置默认指向哪个数据库-->
    <environments default="dev">
        <!--dev 测试环境-->
        <environment id="dev">
            <!-- 采用JDBC方式对数据库事务进行commit/rollback -->
            <transactionManager type="JDBC"></transactionManager>
            <!--采用连接池方式管理数据库连接-->
            <dataSource type="POOLED">            
        <!--驱动-->
                <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <!--配置数据库地址,端口号,数据库名称,  &amp;是转义字符,  避免乱码UTF-8   -->
                <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8"/>
        <!--配置数据库地址  用户,密码,连接池大小参数 -->

                <property name="user" value="root"/>
                <property name="password" value="root"/>
                <property name="initialPoolSize" value="5"/>
                <property name="maxPoolSize" value="20"/>
                <property name="minPoolSize" value="5"/>
                <!--...-->
            </dataSource>
        </environment>

     <!--prd 生产环境>
        <environment id="prd">
            <!-- 采用JDBC方式对数据库事务进行commit/rollback -->
            <transactionManager type="JDBC"></transactionManager>
            <!--采用连接池方式管理数据库连接-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.1.155:3306/babytun?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mappers/goods.xml"/>
        <mapper resource="mappers/goods_detail.xml"/>
    </mappers>
</configuration>

 

12.映射配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="goods">
    <!--开启了二级缓存
        eviction是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除
            1.LRU – 最近最久未使用:移除最长时间不被使用的对象。
            O1 O2 O3 O4 .. O512
            14 99 83 1     893
            2.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
            3.SOFT – 软引用:移除基于垃圾收集器状态和软引用规则的对象。
            4.WEAK – 弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象。
    -->
    <cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>
    <select id="selectAll" resultType="com.imooc.mybatis.entity.Goods" useCache="false">
        select * from t_goods order by goods_id desc limit 10
    </select>
    <!-- 单参数传递,使用parameterType指定参数的数据类型即可,SQL中#{value}提取参数-->
    <select id="selectById" parameterType="Integer" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods where  goods_id = #{value}
    </select>

    <!-- 多参数传递时,使用parameterType指定Map接口,SQL中#{key}提取参数 -->
    <select id="selectByPriceRange" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods
        where
          current_price between  #{min} and #{max}
        order by current_price
        limit 0,#{limt}
    </select>

    <!-- 利用LinkedHashMap保存多表关联结果
        MyBatis会将每一条记录包装为LinkedHashMap对象
        key是字段名  value是字段对应的值 , 字段类型根据表结构进行自动判断
        优点: 易于扩展,易于使用
        缺点: 太过灵活,无法进行编译时检查
     -->
    <select id="selectGoodsMap" resultType="java.util.LinkedHashMap" flushCache="true">
        select g.* , c.category_name,'1' as test from t_goods g , t_category c
        where g.category_id = c.category_id
    </select>

    <!--结果映射-->
    <resultMap id="rmGoods" type="com.imooc.mybatis.dto.GoodsDTO">
        <!--设置主键字段与属性映射-->
        <id property="goods.goodsId" column="goods_id"></id>
        <!--设置非主键字段与属性映射-->
        <result property="goods.title" column="title"></result>
        <result property="goods.originalCost" column="original_cost"></result>
        <result property="goods.currentPrice" column="current_price"></result>
        <result property="goods.discount" column="discount"></result>
        <result property="goods.isFreeDelivery" column="is_free_delivery"></result>
        <result property="goods.categoryId" column="category_id"></result>
        <result property="category.categoryId" column="category_id"></result>
        <result property="category.categoryName" column="category_name"></result>
        <result property="category.parentId" column="parent_id"></result>
        <result property="category.categoryLevel" column="category_level"></result>
        <result property="category.categoryOrder" column="category_order"></result>


        <result property="test" column="test"/>
    </resultMap>
    <select id="selectGoodsDTO" resultMap="rmGoods">
        select g.* , c.*,'1' as test from t_goods g , t_category c
        where g.category_id = c.category_id
    </select>
    <!--flushCache="true"在sql执行后强制清空缓存-->
    <insert id="insert" parameterType="com.imooc.mybatis.entity.Goods" flushCache="true">
        INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
        VALUES (#{title} , #{subTitle} , #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId})
      <!--<selectKey resultType="Integer" keyProperty="goodsId" order="AFTER">-->
          <!--select last_insert_id()-->
      <!--</selectKey>-->
    </insert>

    <update id="update" parameterType="com.imooc.mybatis.entity.Goods">
        UPDATE t_goods
        SET
          title = #{title} ,
          sub_title = #{subTitle} ,
          original_cost = #{originalCost} ,
          current_price = #{currentPrice} ,
          discount = #{discount} ,
          is_free_delivery = #{isFreeDelivery} ,
          category_id = #{categoryId}
        WHERE
          goods_id = #{goodsId}
    </update>
    <!--delete from t_goods where goods_id in (1920,1921)-->
    <delete id="delete" parameterType="Integer">
        delete from t_goods where goods_id = #{value}
    </delete>

    <select id="selectByTitle" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods where title = #{title}
        ${order}
    </select>

    <select id="dynamicSQL" parameterType="java.util.Map" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods
        <where>
          <if test="categoryId != null">
              and category_id = #{categoryId}
          </if>
          <if test="currentPrice != null">
              and current_price &lt; #{currentPrice}
          </if>
        </where>
    </select>

    <!--
        resultMap可用于说明一对多或者多对一的映射逻辑
        id 是resultMap属性引用的标志
        type 指向One的实体(Goods)
    -->
    <resultMap id="rmGoods1" type="com.imooc.mybatis.entity.Goods">
        <!-- 映射goods对象的主键到goods_id字段 -->
        <id column="goods_id" property="goodsId"></id>
        <!--
            collection的含义是,在
            select * from t_goods limit 0,1 得到结果后,对所有Goods对象遍历得到goods_id字段值,
            并代入到goodsDetail命名空间的findByGoodsId的SQL中执行查询,
            将得到的"商品详情"集合赋值给goodsDetails List对象.
        -->
        <collection property="goodsDetails" select="goodsDetail.selectByGoodsId"
                    column="goods_id"/>
    </resultMap>
    <select id="selectOneToMany" resultMap="rmGoods1">
        select * from t_goods limit 0,10
    </select>

    <select id="selectPage" resultType="com.imooc.mybatis.entity.Goods">
        select * from t_goods where current_price &lt; 1000
    </select>

    <!--INSERT INTO table-->
    <!--VALUES ("a" , "a1" , "a2"),("b" , "b1" , "b2"),(....)-->
    <insert id="batchInsert" parameterType="java.util.List">
        INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
        VALUES
        <foreach collection="list" item="item" index="index" separator=",">
            (#{item.title},#{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId})
        </foreach>
    </insert>
    <!--in (1901,1902)-->
    <delete id="batchDelete" parameterType="java.util.List">
        DELETE FROM t_goods WHERE goods_id in
        <foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>
</mapper>

 

posted on 2024-04-18 17:17  熊本熊の熊  阅读(13)  评论(0)    收藏  举报