MyBatis高级特性

1.日志

用于记录系统操作记录,保存历史数据,诊断问题

1.1.SLF4j与Logback

日志门面:统一的对外接口

1-1.jpg

pom中插入依赖

    
        ch.qos.logback
        logback-classic
        1.2.3
    

resources下面添加logback.xml日志配置文件



    
        
            
            [%thread] %d{HH:mm:ss.SSS}  %-5level %logger{36} - %msg%n
        
    
    
    
        
    

2.动态SQL

根据参数数据动态组织SQL

goods.xml:



调用:

@Test
public void testDynamicSQL() throws Exception {
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    Map param = new HashMap();
    param.put("category", 44);
    param.put("currentPrice", 500);
    //可以不加namespace,确保id是唯一即可
    List list = session.selectList("goods.dynamicSQL",param);
    for (int i = 0; i < list.size(); i++) {
        Goods goods =  list.get(i);
        System.out.println(goods.getTitle());
    }
    MyBatisUtils.closeSession(session);
}

3.缓存

主要是MyBatis二级缓存

  • 一级缓存默认开启,缓存范围SqlSession会话
  • 二级缓存手动开启,缓存范围是Mapper Namespace
1-2.jpg

3.1.二级缓存运行规则

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

一级缓存的测试代码:

@Test
public void testLv1Cache() {
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    Goods goods = session.selectOne("goods.selectById",1603);
    Goods goods1 = session.selectOne("goods.selectById",1603);
    System.out.println("goods hashCode:" + goods.hashCode() + "-goods1 hashCode:" +  goods1.hashCode());
    MyBatisUtils.closeSession(session);



    SqlSession session1 = null;
    session1 = MyBatisUtils.openSession();
    Goods goods2 = session1.selectOne("goods.selectById",1603);
    Goods goods3 = session1.selectOne("goods.selectById",1603);

    System.out.println("goods2 hashCode:" + goods2.hashCode() + "-goods3 hashCode:" +  goods3.hashCode());
    MyBatisUtils.closeSession(session1);
}

运行结果:

goods hashCode:574268151-goods1 hashCode:574268151
goods2 hashCode:423583818-goods3 hashCode:423583818

可以看到同一个session的hashCode相同,说明是同一个对象,并且debug日志也只会执行一次sql查询,如果在goods和goods1之间插入session.commit()方法,则goods和goods1则会是两个不同的对象。

二级缓存测试代码:

goods.xml中添加




测试代码与一级缓存一样不变

运行结果:

goods hashCode:270095066-goods1 hashCode:270095066
goods2 hashCode:270095066-goods3 hashCode:270095066

说明开启了二级缓存后,不同session也会公用一个缓存数据。

3.2.二级缓存参数说明

二级缓存相关:


    
    
...

单条相关:

    
     

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

4.多表级联查询

1-3.jpg

4.1.一对多查询

商品与商品图片详情就是1对多的关系

开发步骤:

4.1.1.resources下创建goods_detail.xml




    

4.1.2.goods.xml中配置一对多



    
    
    



4.1.3.mybatis-config.xml中加入应用

加入对goods_detail.xml的引用


4.1.4.调用测试

@Test
public void testOneToMany(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    List list = session.selectList("goods.selectOneToMany");
    for (int i = 0; i < list.size(); i++) {
        Goods goods =  list.get(i);
        System.out.println(goods.getTitle() + " : " +goods.getGoodsDetails().size());
    }
    MyBatisUtils.closeSession(session);
}

4.2.多对一查询

商品图片详情与商品是多对一

开发步骤:

4.2.1.mapper.xml配置

goods_detail.xml中添加多对一查询语句和resultMap:



    
    
    
    
    
    




4.2.2.调用

@Test
public void testManyToOne(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    List list = session.selectList("goodsDetail.selectManyToOne");
    for (int i = 0; i < list.size(); i++) {
        GoodsDetail goodsDetail =  list.get(i);
        if (goodsDetail.getGoods() == null)
            continue;
        System.out.println(goodsDetail.getGdPicUrl() + " : " + goodsDetail.getGoods().getTitle());
    }
    MyBatisUtils.closeSession(session);

}

5.分页PageHelper

原理:

  • 当前数据查询使用语句

select * from tab limit 0,10

  • 总记录数查询

select count(*) from tab

  • 程序计算总页数、当前页、上一页下一页码

5.1.PageHelper使用流程

  • maven引入PageHelper与jsqlparser

      
          com.github.pagehelper
          pagehelper
          5.1.10
      
      
          com.github.jsqlparser
          jsqlparser
          2.0
      
    
  • mybatis-config.xml增加Plugin配置

      
      
          
              
              
              
              
          
      
    
  • mapper.xml中添加查询sql

    
    
  • 代码中使用PageHelper.startPage()自动分页
    @Test
    public void testPageHelper(){
        SqlSession session = null;
        session = MyBatisUtils.openSession();
        PageHelper.startPage(2, 10);
        Page 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());
        List data = page.getResult();//当前页数据
        for (int i = 0; i < data.size(); i++) {
            Goods goods =  data.get(i);
            System.out.println(goods.getTitle());
        }
        MyBatisUtils.closeSession(session);
    }


    --结果

    总页数:181
    总记录数:1810
    开始行号:10
    当前页码:20
    康泰 家用智能胎心仪 分体探头操作方便 外放聆听 与家人分享宝宝心声

6.C3P0连接池

配置流程:

  • maven引入c3p0的引用

      
          com.mchange
          c3p0
          0.9.5.4
      
    
  • 创建C3P0DataSourceFactory

      //C3P0与MyBatis兼容使用的数据源工厂类
      public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
          public C3P0DataSourceFactory(){
              this.dataSource = new ComboPooledDataSource();
          }
      }
    
  • mybatis.xml中引入datasource配置

        
        
            
            
            
            
            
            
            
        

剩下的不便

7.MyBatis批处理

在mapper.xml中使用foreach标签




    INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id)
    VALUES
    
        (#{item.title}, #{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId})
    

调用:

@Test
//分别插入
public void testBatchInsert1(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    long st = new Date().getTime();
    for (int i = 0; i < 1000; 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);
        session.insert("goods.insert", goods);
    }
    session.commit();
    long et = new Date().getTime();
    System.out.println("执行时间:" + (et - st) + "毫秒");
    MyBatisUtils.closeSession(session);
}

@Test
//批量插入
public void testBatchInsert2(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    long st = new Date().getTime();
    List list = new ArrayList();
    for (int i = 0; i < 1000; 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);
        list.add(goods);
    }
    session.insert("goods.batchInsert",list);
    session.commit();
    long et = new Date().getTime();
    System.out.println("执行时间:" + (et - st) + "毫秒");
    MyBatisUtils.closeSession(session);
}

分别插入的时间:

执行时间:976毫秒

批处理插入的时间:

执行时间:679毫秒

由此可见批处理的效率很高

批量删除:



    DELETE FROM t_goods WHERE goods_id in
    
        #{item}
    


--调用

@Test
//批量删除
public void testBatchDelete(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    long st = new Date().getTime();
    List list = new ArrayList();
    for (int i = 4670; i <= 4677; i++) {
        list.add(i);
    }
    session.insert("goods.batchDelete",list);
    session.commit();
    long et = new Date().getTime();
    System.out.println("执行时间:" + (et - st) + "毫秒");
    MyBatisUtils.closeSession(session);
}

8.注解

mapper可以通过注解方式配置

新建GoodsDAO:

public interface GoodsDAO {

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

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

    @Select("select * from t_goods")
    //配置返回值map
    @Results({
            @Result(column = "goods_id", property = "goodsId", id = true),
            @Result(column = "current_price", property = "currentPrice")
    })
    List selectAll();
}

mybatis-config.xml中配置dao




    

调用:

@Test
public void testSelect(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class);
    List list = goodsDAO.selectByPriceRange(100f, 500f, 20);
    System.out.println(list.size());
    MyBatisUtils.closeSession(session);
}

@Test
public void testInsert(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class);
    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.insert(goods);
    session.commit();
    MyBatisUtils.closeSession(session);
}

@Test
public void testSelectAll(){
    SqlSession session = null;
    session = MyBatisUtils.openSession();
    GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class);
    List goodsDTOS = goodsDAO.selectAll();
    System.out.println(goodsDTOS.size());
    MyBatisUtils.closeSession(session);
}

你可能感兴趣的:(MyBatis高级特性)