MyBatis进阶

内容纲要

MyBatis日志管理

  • 日志文件是用于记录系统操作事件的记录文件或文件集合
  • 日志保存历史数据,是诊断问题以及理解系统活动的重要依据

    SLF4j与Logback

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
           <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
       </encoder>
   </appender>
    <!--
        日志输出级别(优先级高到低):
        error: 错误 - 系统的故障日志
        warn: 警告 - 存在风险或使用不当的日志
        info: 一般性消息
        debug: 程序内部用于调试信息
        trace: 程序运行的跟踪信息
     -->
    <root level="debug">
        <appender-ref ref="console"/>
    </root>
</configuration>

动态SQL

  • 动态SQL是指根据参数数据动态组织SQL的技术

    MyBatis二级缓存

  • 一级缓存默认开启,缓存范围SqlSession会话
  • 二级缓存手动开启,属于范围Mapper Namespace

    缓存的范围

    二级缓存运行规则

  • 二级开启后默认所有查询操作均使用缓存
  • 写操作commit提交时对该namespace缓存强制清空
  • 配置useCache=false可以不用缓存
  • 配置flushCache=true代表强制清空缓存
 <!--开启了二级缓存
        eviction是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除
            1.LRU – 最近最少使用的:移除最长时间不被使用的对象。
            O1 O2 O3 O4 .. O512
            14 99 83 1     893
            2.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
            3.SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
            4.WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

        flushInterval 代表间隔多长时间自动清空缓存,单位毫秒,600000毫秒 = 10分钟
        size 缓存存储上限,用于保存对象或集合(1个集合算1个对象)的数量上限
        readOnly 设置为true ,代表返回只读缓存,每次从缓存取出的是缓存对象本身.这种执行效率较高
                 设置为false , 代表每次取出的是缓存对象的"副本",每一次取出的对象都是不同的,这种安全性较高
    -->
    <cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>
    <!-- useCache="false"代表不使用缓存 **全局查询** -->
    <!--flushCache="true"在sql执行后强制清空缓存 **写添加**,清空的同时,查询出来的结果不会方法缓存中-->

MyBatis多表级联查询

1到多

实体类对象1的一方关联上多的一方
多的一方采用List类型

<!--
    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="selectByGoodsId" parameterType="Integer"
        resultType="com.imooc.mybatis.entity.GoodsDetail">
    select * from t_goods_detail where goods_id = #{value}
</select>

多到1

实体类对象多的一方关联上1的一方

<resultMap id="rmGoodsDetail" type="com.imooc.mybatis.entity.GoodsDetail">
    <id column="gd_id" property="gdId"/>
    <result column="goods_id" property="goodsId"/>
    <association property="goods" select="goods.selectById" column="goods_id"></association>
</resultMap>
<select id="selectManyToOne" resultMap="rmGoodsDetail">
    select * from t_goods_detail limit 0,20
</select>

分页插件PageHelper

  • 当前页数据查询 - select * form tab limit 0,10
  • 总记录数查询 - select count(*) from tab
  • 程序计算总页数、上一页页码、下一页页码
public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /*获取页面传过来的当前页码*/
    String pageNum = request.getParameter("pageNum");
    /*如果第一次查询时没有分页页面,默认是第一页*/
    if(pageNum==null) pageNum="1";
   /* 设置起始查询页码,以及每页条数*/
    PageHelper.startPage(Integer.parseInt(pageNum),20);
   /* 查询蛋糕*/
    List<Cake> list = cakeBiz.getAll();
    /*把查询的结果封装到PageInfo中*/
    PageInfo pageInfo = PageInfo.of(list);
   /* 把pageInfo放到域中并转发到蛋糕列表页中*/
    request.setAttribute("pageInfo",pageInfo);
    request.getRequestDispatcher("/WEB-INF/pages/admin/cake_list.jsp").forward(request,response);
}
<div class="col-xs-12 col-md-9 text-right">
    <%--list8--%>
    <form action="/admin/Cake/list.do" method="post">
        共${pageInfo.total}条 ${pageInfo.pageNum}/${pageInfo.pages}
        <div class="btn-group">
            <button type="submit" name="pageNum" value="${pageInfo.pageNum-1}"
                    class="btn btn-default light">
                <i class="fa fa-chevron-left"></i>
            </button>
            <button type="submit" name="pageNum" value="${pageInfo.pageNum+1}"
                    class="btn btn-default light">
                <i class="fa fa-chevron-right"></i>
            </button>
        </div>
    </form>
</div>

PageHelper使用流程

  • maven引入PageHelper与jspparser
  • mybatis-config.xml增加Plugin配置
  • 代码中使用PageHelper.startPager()自动分页
    <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
    </dependency>
    <dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>2.0</version>
    </dependency>
    =================================
    <!--启用Pagehelper分页插件-->
    <plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!--设置数据库类型-->
        <property name="helperDialect" value="mysql"/>
        <!--分页合理化-->
        <property name="reasonable" value="true"/>
    </plugin>
    </plugins>
    ======spring+mybatis+pagerhelper整合===========
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源,关联申请的数据源-->
        <property name="dataSource" ref="dataSoure"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="oes.entity"/>
        <!--配置pageHelper-->
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageHelper">
                    <property name="properties">
                        <value>
                            <!--数据源类型:mysql, mariadb, sqlite, oracle, hsqldb, postgresql, sqlserver, db2, informix, h2, sqlserver2012-->
                            helperDialect=mysql
                            <!--分页合理化参数,设置为true时,pageNum<=0时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。-->
                            reasonable=true
                        </value>
                    </property>
                </bean>
            </array>
        </property>
    </bean>

    不同数据库分页的实现原理

  • MySQL分页
    select * form table limit 10,20
    第一个参数:起始行号
    第二个参数:从第一个参数往后去多少行
  • Oracle
select t3.* from (
    select t2.*, rownum as row num from (
        select * from table order by id asc
    ) t2 where rownum< = 20
) t3
where t2.row num> 1 1
  • SQL Server 2000
select top 3 * from table
where
    id not in.
    (select top 15 id from table)
  • SQL Server 2012+
select * from table order by id
    offset 4 rows fetch next 5 rows only

MyBatis整合C3P0连接池

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.4</version>
</dependency>
=====创建一个C3P0DataSourceFactory类==========
/**
 * C3P0与MyBatis兼容使用的数据源工厂类
 */
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
    public C3P0DataSourceFactory(){
        this.dataSource = new ComboPooledDataSource();
    }
}
=================config==================
<environment id="dev">
    <!-- 采用JDBC方式对数据库事务进行commit/rollback -->
    <transactionManager type="JDBC"></transactionManager>
    <!--采用连接池方式管理数据库连接-->
    <!--<dataSource type="POOLED">-->
    <dataSource type="com.imooc.mybatis.datasource.C3P0DataSourceFactory">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://47.114.2.235:3306/jdbc?useUnicode=true&characterEncoding=UTF-8"/>
        <property name="user" value="jdbc"/>
        <property name="password" value="jdbc"/>
        <property name="initialPoolSize" value="5"/>
        <property name="maxPoolSize" value="20"/>
        <property name="minPoolSize" value="5"/>
        <!--...-->
    </dataSource>
</environment>

MyBatis批量处理

  • 批量插入
<!--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>

MyBatis注解开发

public interface GoodsDAO {
    @Select("select * from t_goods where current_price between  #{min} and #{max} order by current_price limit 0,#{limt}")
    public List<Goods> selectByPriceRange(@Param("min") Float min ,@Param("max") Float max ,@Param("limt") Integer limt);

    @Insert("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>
    @SelectKey(statement = "select last_insert_id()" , before = false , keyProperty = "goodsId" , resultType = Integer.class)
    public int insert(Goods goods);

    @Select("select * from t_goods")
    //<resultMap>
    @Results({
            //<id>
          @Result(column = "goods_id" ,property = "goodsId" , id = true) ,
            //<result>
            @Result(column = "title" ,property = "title"),
            @Result(column = "current_price" ,property = "currentPrice")
    })
    public List<GoodsDTO> selectAll();
}
THE END
分享
二维码
< <上一篇
下一篇>>