0
点赞
收藏
分享

微信扫一扫

MyBatis进阶


MyBatis日志管理

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

SLF4j与Logback

MyBatis进阶_java


演示

添加依赖

pom.xml中

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.3</version>
</dependency>

MyBatis进阶_xml_02


MyBatis进阶_maven_03


添加完成后 控制台出现日志信息

MyBatis进阶_mybatis_04


日志自定义

在resources目录下新增logback.xml文件

MyBatis进阶_xml_05

<?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>

再次运行时 日志时间换了位置

MyBatis进阶_mybatis_06

动态SQL

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

MyBatis进阶_xml_07


goods.xml中

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

MyBatis进阶_maven_08


MybatisTestor中

/**
* 动态SQL语句
* @throws Exception
*/
@Test
    public void testDynamicSQL() throws Exception {
    SqlSession session = null;
try{
    session = MyBatisUtils.openSession();
    Map param = new HashMap();
    param.put("categoryId", 44);
    param.put("currentPrice", 500);
    //查询条件
    List<Goods> list = session.selectList("goods.dynamicSQL", param);
    for(Goods g:list){
        System.out.println(g.getTitle() + ":" +
                           g.getCategoryId()  + ":" + g.getCurrentPrice());

    }
}catch (Exception e){
    throw e;
}finally {
    MyBatisUtils.closeSession(session);
}
}

运行结果

MyBatis进阶_java_09

MyBatis二级缓存

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

MyBatis进阶_java_10


SqlSession一级缓存使用率不高

二级缓存被所有SqlSession共享

二级缓存运行规则

  • 二级开启后默认所有查询操作均使用缓存
  • 写操作commit提交时对该namespace缓存强制清空
  • 配置useCache=false可以不用缓存
  • 配置flushCache=true代表强制清空缓存

验证一级缓存
测试代码
MybatisTestor.java中

@Test
    public void testLv1Cache() throws Exception{
    SqlSession session = null;
try{
    session = MyBatisUtils.openSession();
    Goods goods = session.selectOne("goods.selectById",1603);
    Goods goods1 = session.selectOne("goods.selectById",1603);
    System.out.println(goods.hashCode()+"--"+goods1.hashCode();
}catch (Exception e){
    throw e;
}finally {
    MyBatisUtils.closeSession(session);
}
}

输出的哈希地址一致

MyBatis进阶_mybatis_11


两个session情况

@Test
    public void testLv1Cache() throws Exception{
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            Goods goods = session.selectOne("goods.selectById",1603);
            Goods goods1 = session.selectOne("goods.selectById",1603);
            System.out.println(goods.hashCode()+"--"+goods1.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
        try{
            session = MyBatisUtils.openSession();
            Goods goods = session.selectOne("goods.selectById",1603);
            Goods goods1 = session.selectOne("goods.selectById",1603);
            System.out.println(goods.hashCode()+"--"+goods1.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }

MyBatis进阶_mybatis_12


一级缓存只存在一个session中

执行commit强制清空

@Test
    public void testLv1Cache() throws Exception{
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            Goods goods = session.selectOne("goods.selectById",1603);
            session.commit();
            Goods goods1 = session.selectOne("goods.selectById",1603);
            System.out.println(goods.hashCode()+"--"+goods1.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }

MyBatis进阶_maven_13


开启二级缓存

goods.xml中添加

<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>

MyBatis进阶_xml_14


验证二级缓存

@Test
    public void testLv2Cache() throws Exception{
    SqlSession session = null;
try{
    session = MyBatisUtils.openSession();
    Goods goods = session.selectOne("goods.selectById",1603);
    System.out.println(goods.hashCode());
}catch (Exception e){
    throw e;
}finally {
    MyBatisUtils.closeSession(session);
}
try{
    session = MyBatisUtils.openSession();
    Goods goods = session.selectOne("goods.selectById",1603);
    System.out.println(goods.hashCode());
}catch (Exception e){
    throw e;
}finally {
    MyBatisUtils.closeSession(session);
}
}

MyBatis进阶_mybatis_15

<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>
<!--
  	eviction是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除
            1.LRU – 最近最久未使用:移除最长时间不被使用的对象。
            O1 O2 O3 O4 .. O512
            14 99 83 1     893
            2.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
            3.SOFT – 软引用:移除基于垃圾收集器状态和软引用规则的对象。
            4.WEAK – 弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象。
  flushInterval 代表间隔多长时间自动清空缓存,单位毫秒
  size 缓存存储上限,用于保存对象或集合(1个集合算1个对象)的数量上限
	readOnly 设置为true,代表返回只读缓存,每次从缓存取出的是缓存对象本身,执行效率较高
           设置为false,代表每次取出的是缓存对象的“副本”,每一次取出的对象都是不同的,安全性较高
-->

MyBatis多表级联查询

MyBatis进阶_xml_16


商品和详情对象关联查询

在entity目录下创建GoodsDetail.java

package com.mybatis.entity;

public class GoodsDetail {
    private Integer gdId;
    private Integer goodsId;
    private String gdPicUrl;

    public Integer getGdId() {
        return gdId;
    }

    public void setGdId(Integer gdId) {
        this.gdId = gdId;
    }

    public Integer getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(Integer goodsId) {
        this.goodsId = goodsId;
    }

    public String getGdPicUrl() {
        return gdPicUrl;
    }

    public void setGdPicUrl(String gdPicUrl) {
        this.gdPicUrl = gdPicUrl;
    }

    public Integer getGdOrder() {
        return gdOrder;
    }

    public void setGdOrder(Integer gdOrder) {
        this.gdOrder = gdOrder;
    }

    private Integer gdOrder;
}

MyBatis进阶_xml_17


mappers目录下创建goods_detail.xml

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

在Goods.java中添加一个List

MyBatis进阶_xml_18


goods.xml中添加

<!--
        resultMap可用于说明一对多或者多对一的映射逻辑
        id 是resultMap属性引用的标志
        type 指向One的实体(Goods)
    -->
    <resultMap id="rmGoods1" type="com.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>

mybatis-config.xml中添加

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

MyBatis进阶_mybatis_19


测试用例:

@Test
    public void testOneToMany() throws Exception {
    SqlSession session = null;
try {
    session = MyBatisUtils.openSession();
    List<Goods> list = session.selectList("goods.selectOneToMany");
    for(Goods goods:list) {
        System.out.println(goods.getTitle() + ":" + goods.getGoodsDetails().size());
    }
} catch (Exception e) {
    throw e;
} finally {
    MyBatisUtils.closeSession(session);
}
}

MyBatis进阶_xml_20


MyBatis进阶_maven_21

ManyToOne对象关联查询

在GoodsDetail.java中添加

private Goods goods;

    public Goods getGoods() {
        return goods;
    }

    public void setGoods(Goods goods) {
        this.goods = goods;
    }

MyBatis进阶_xml_22


在goods_detail.xml中添加描述

<resultMap id="rmGoodsDetail" type="com.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,1
    </select>

测试用例

/**
* 测试多对一对象关联映射
*/
@Test
    public void testManyToOne() throws Exception {
    SqlSession session = null;
try {
    session = MyBatisUtils.openSession();
    List<GoodsDetail> list = session.selectList("goodsDetail.selectManyToOne");
    for(GoodsDetail gd:list) {
        System.out.println(gd.getGdPicUrl() + ":" + gd.getGoods().getTitle());
    }
} catch (Exception e) {
    throw e;
} finally {
    MyBatisUtils.closeSession(session);
}
}

MyBatis进阶_mybatis_23


数据量增到20条后

MyBatis进阶_缓存_24


MyBatis进阶_xml_25

PageHelper分页插件

分页查询的麻烦事

  • 当前页数据查询-select * from tab limit 0,10
  • 总记录数查询-select count(*) from tab
  • 程序计算总页数、上一页页码、下一页页码

PageHelper使用流程

  • maven引入PageHelper与jsqlparser
  • mybatis-config.xml增加Plugin配置
  • 代码中使用PageHelper.startPage()自动分页

在pom.xml中引入插件

<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>

MyBatis进阶_xml_26


在mybatis-config.xml配置插件

<plugins>
  <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--设置数据库类型-->
            <property name="helperDialect" value="mysql"/>
            <!--分页合理化-->
            <property name="reasonable" value="true"/>
        </plugin>
</plugins>

MyBatis进阶_mybatis_27

在goods.xml中添加

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

MyBatis进阶_mybatis_28


测试

MybatisTestor.java中

@Test
    public void testSelectPage(){
        SqlSession session=null;
        try{
            session=MyBatisUtils.openSession();
            /*startPage方法会自动将下一次查询进行分页*/
            PageHelper.startPage(2,10);
            Page<Goods> page = (Page) session.selectList("goods.selectPage");
            System.out.println("总页数:"+page.getPages());
            System.out.println("总记录数:"+page.getTotal());
            System.out.println("开始行号:"+page.getStartRow());
            System.out.println("结束行号:"+page.getEndRow());
            System.out.println("当前页码:"+page.getPageNum());
            List<Goods> data = page.getResult();//当前页数据
            for(Goods g:data){
                System.out.println(g.getTitle());
            }
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }

MyBatis进阶_maven_29


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

MySQL分页:select * from 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>11

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连接池

添加依赖
pom.xml中

<dependency>
  <groupId>com.mchange</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.5.4</version>
</dependency>

创建C3P0DataSourceFactory.java

MyBatis进阶_xml_30

package com.mybatis.datasource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;

public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
    public C3P0DataSourceFactory(){
        this.dataSource=new ComboPooledDataSource();
    }
}

修改连接池配置

<dataSource type="com.mybatis.datasource.C3P0DataSourceFactory">
  <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/babytun?useUnicode=true&characterEncoding=UTF-8"/>
  <property name="user" value="root"/>
  <property name="password" value="123456"/>
  <property name="initialPoolSize" value="5"/>
  <property name="maxPoolSize" value="20"/>
  <property name="minPoolSize" value="5"/>
  <!--...-->
</dataSource>

MyBatis进阶_maven_31

MyBatis批处理

批量插入
在goods.xml中编写

<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>

测试 MybatisTestor.java

@Test
    public void testInsert1() throws Exception {
        SqlSession session = null;
try{
    long st = new Date().getTime();
    session = MyBatisUtils.openSession();
    List list = new ArrayList();
    for(int i = 0 ; i < 10000 ; i++) {
        Goods goods = new Goods();
        goods.setTitle("测试商品");
        goods.setSubTitle("测试子标题");
        goods.setOriginalCost(200f);
        goods.setCurrentPrice(100f);
        goods.setDiscount(0.5f);
        goods.setIsFreeDelivery(1);
        goods.setCategoryId(43);
        //insert()方法返回值代表本次成功插入的记录总数

        session.insert("goods.insert" , goods);
    }

    session.commit();//提交事务数据
    long et = new Date().getTime();
    System.out.println("执行时间:" + (et-st) + "毫秒");
    //            System.out.println(goods.getGoodsId());
}catch (Exception e){
    if(session != null){
        session.rollback();//回滚事务
    }
    throw e;
}finally {
    MyBatisUtils.closeSession(session);
}
}

MyBatis进阶_mybatis_32


批量删除

goods.xml

<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>

测试 MybatisTestor.java

@Test
    public void testBatchDelete() throws Exception {
        SqlSession session = null;
try {
    long st = new Date().getTime();
    session = MyBatisUtils.openSession();
    List list = new ArrayList();
    for(int i=1931;i<=11930;i++)
        list.add(i);
    session.delete("goods.batchDelete", list);
    session.commit();//提交事务数据
    long et = new Date().getTime();
    System.out.println("执行时间:" + (et - st) + "毫秒");
    //            System.out.println(goods.getGoodsId());
} catch (Exception e) {
    if (session != null) {
        session.rollback();//回滚事务
    }
    throw e;
} finally {
    MyBatisUtils.closeSession(session);
}
}

MyBatis进阶_缓存_33

Mybatis注解开发方式

MyBatis常用注解

注解

对应XML

说明

@Insert

新增SQL

@Update

更新SQL

@Delete

删除SQL

@Select

查询SQL

@Param


参数映射

@Results

结果映射

@Result

字段映射

创建GoodsDAO接口

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();
}

mybatis-config.xml中配置

<mappers>
  <!--<mapper class="com.imooc.mybatis.dao.GoodsDAO"/>-->
  <package name="com.imooc.mybatis.dao"/>
</mappers>

测试

//JUNIT单元测试类
public class MyBatisTestor {

    @Test
    public void testSelectByPriceRange() throws Exception {
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class);
            List<Goods> list = goodsDAO.selectByPriceRange(100f, 500f, 20);
            System.out.println(list.size());
        }catch (Exception e){
            throw e;
        } finally {
            MyBatisUtils.closeSession(session);

        }
    }

    /**
     * 新增数据
     * @throws Exception
     */
    @Test
    public void testInsert() throws Exception {
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            Goods goods = new Goods();
            goods.setTitle("测试商品");
            goods.setSubTitle("测试子标题");
            goods.setOriginalCost(200f);
            goods.setCurrentPrice(100f);
            goods.setDiscount(0.5f);
            goods.setIsFreeDelivery(1);
            goods.setCategoryId(43);
            GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class);
            //insert()方法返回值代表本次成功插入的记录总数
            int num = goodsDAO.insert(goods);
            session.commit();//提交事务数据
            System.out.println(goods.getGoodsId());
        }catch (Exception e){
            if(session != null){
                session.rollback();//回滚事务
            }
            throw e;
        }finally {
            MyBatisUtils.closeSession(session);
        }
    }

    @Test
    public void testSelectAll() throws Exception {
        SqlSession session = null;
        try{
            session = MyBatisUtils.openSession();
            GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class);
            List<GoodsDTO> list = goodsDAO.selectAll();
            System.out.println(list.size());
        }catch (Exception e){
            throw e;
        } finally {
            MyBatisUtils.closeSession(session);

        }
    }
}


举报

相关推荐

0 条评论