MyBatis笔记二
创始人
2025-05-28 23:26:44
  • 日志文件是用于记录系统操作时间的记录文件或文件集合
  • 日志保存历史记录,是诊断问题及理解系统活动的重要依据

日志门面SLF4J/Apache Commons-Logging===桥接==>日志实现log4j/logbacl/java.util.logging(jul)

一、日志管理

1.1 pom.xml添加依赖

ch.qos.logback logback-classic 1.2.3 test

控制台输出

1.2 自定义日志

resource下新建文件,命名强制为logback.xml

level日志级别

  • error 错误 系统的故障日志
  • warn 警告 存在风险或使用不当的日志
  • info 一般性信息
  • debug 程序内部用于调试信息
  • trace 程序运行的跟踪信息

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

二、动态SQL

动态sql是根据参数数据动态组织sql的技术

mapper文件编写查询语句

或者

and category_id=#{categoryId} and current_price < #{currentPrice}

编写测试文件

@Test public void dynamic() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); Map params = new HashMap(); params.put("categoryId", 44); params.put("currentPrice", 500); List list = sqlSession.selectList("goods.dynamicSQL", params); sqlSession.commit(); // 提交事务数据 for(Goods goods:list ){ System.out.println(goods.getTitle()); } } catch (Exception e) { System.out.println(e); if(sqlSession!=null) { sqlSession.rollback(); } } finally { MybatisUtils.closeSession(sqlSession); } }

三、MyBatis二级缓存

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

3.1 二级缓存运行规则

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

一级缓存

public void testLv1Cache() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); Goods goods = sqlSession.selectOne("goods.selectId", 1603); Goods good1 = sqlSession.selectOne("goods.selectId", 1603); System.out.println(goods.hashCode()); System.out.println(good1.hashCode()); } finally { MybatisUtils.closeSession(sqlSession); } }

打印出hascode相同(一级缓存生命周期SqlSession会话)

添加commit后缓存消失

public void testLv1Cache() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); Goods goods = sqlSession.selectOne("goods.selectId", 1603); sqlSession.commit(); Goods good1 = sqlSession.selectOne("goods.selectId", 1603); System.out.println(goods.hashCode()); System.out.println(good1.hashCode()); } finally { MybatisUtils.closeSession(sqlSession); } }

在映射文件src/java/resource/mapper/goods.xml中开启二级缓存

public void testLv2Cache() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); Goods goods = sqlSession.selectOne("goods.selectId", 1603); sqlSession.commit(); Goods good1 = sqlSession.selectOne("goods.selectId", 1603); System.out.println(goods.hashCode()); System.out.println(good1.hashCode()); } finally { MybatisUtils.closeSession(sqlSession); } try { sqlSession = MybatisUtils.openSession(); Goods goods = sqlSession.selectOne("goods.selectId", 1603); sqlSession.commit(); Goods good1 = sqlSession.selectOne("goods.selectId", 1603); System.out.println(goods.hashCode()); System.out.println(good1.hashCode()); } finally { MybatisUtils.closeSession(sqlSession); } }

只查询了一次,之后使用缓存

3.2 cache标签属性

eviction是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清楚

  • LRU 最久未使用:移除最长时间未使用
  • FIFO 先进先出:按对象进入混存的顺序来移除它们
  • SOFT 软引用:移除基于垃圾收集器和软引用规则的对象
  • WEAK 弱饮用:更积极的移除基于垃圾收集器状态和弱勇规则的对象

flushInterval 缓存间隔,间隔时间自动清除

size 最大缓存对象,实体类、list都是一个缓存对象

readOnly 每次缓存取出的是缓存对象本身,效率较高。设置为false,取出的是缓存对象的“副本”,每次取出对象都不同,安全性较高

useCache 是否使用缓存 (list对象少用缓存)

flushCache 执行完语句后立即情况,多用在写操作

四、MyBatis多表级联查询

4.1 一对多查询

创建src/main/java/entity/GoodsDetail.java实体类

package com.gu.entity; public class GoodsDetail { private Integer gdId; private Integer goodsId; private String gdPicUrl; private Integer gdOrder; 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; } }

由于与Goods是1:n关系,添加details

private List goodsDetails; public List getGoodsDetails() { return goodsDetails; } public void setGoodsDetails(List goodsDetails) { this.goodsDetails = goodsDetails; }

创建映射文件resources/mappers/goods_detail.xml

在mybatis-config.xml配置文件中添加映射

在goods改动映射文件

测试查询

@Test public void testOneToMany() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); List list = sqlSession.selectList("goods.selectOneToMany", 1603); for (Goods goods: list) { System.out.println(goods.getTitle()); for (GoodsDetail goodsDetail: goods.getGoodsDetails()) { System.out.println(goodsDetail.getGdPicUrl()); } } } finally { MybatisUtils.closeSession(sqlSession); } }

4.2 多对一查询

多的一方,添加实体,在goodsDetaile中添加Goods实体

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

添加映射的sql方法

测试方法

public void testSelectManyToOne() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); List list = sqlSession.selectList("goodsDetail.selectManyToOne"); for (GoodsDetail gd: list) { System.out.println(gd.getGdPicUrl() + gd.getGoods().getTitle()); } } finally { MybatisUtils.closeSession(sqlSession); } }

五、分页插件(PageHelper)

需要完成的工作:

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

5.1 根据pageHelper官网文档配置

pom.xml配置依赖

com.github.pagehelper pagehelper 5.1.10 com.github.jsqlparser jsqlparser 2.0

mybatis.config.xml配置插件选项

mappers/goods.xml中配置sql语句

测试代码

public void testSelectPage() { SqlSession sqlSession = null; try { sqlSession = MybatisUtils.openSession(); PageHelper.startPage(2, 10); Page page = (Page) sqlSession.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 list = page.getResult(); for (Goods goods: list) { System.out.println(goods.getTitle()); } } finally { MybatisUtils.closeSession(sqlSession); } }

六、MyBatis整合C3P0连接池

C3P0连接池功能较MyBatis更为强大

引入依赖

com.mchange c3p0 0.9.5.4

新建文件存储数据源 java/com/gu/datasource/C3P0DataSourceFactory.java

package com.gu.datasource; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; //c3p0与MyBatis兼容使用的数据源工厂 public class C3P0DataSourceFactory extends UnpooledDataSourceFactory { public C3P0DataSourceFactory() { // 由c3p0创建数据源 this.dataSource = new ComboPooledDataSource(); } }

mybatis-config.xml配置p3c0

七、批处理

mapper映射文件: 插入

insert into t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id) values -- list指代集合,不能随意更改 separator分隔符 (#{item.title}, #{item.subTitle}, #{item.originalCost}, #{item.currentPrice}, #{item.discount}, #{item.isFreeDelivery}, #{item.categoryId} )

mapper映射文件:删除

delete from t_goods where goods_id in #{item}

测试代码

sqlSession = MybatisUtils.openSession(); List list = new ArrayList<>(); long st = new Date().getTime(); for(int i = 0; i < 1000; i++){ Goods goods = new Goods(); goods.setTitle("测试商品01"); goods.setSubTitle("测试子标题"); goods.setOriginalCost(200f); goods.setCurrentPrice(100f); goods.setIsFreeDelivery(1); goods.setDiscount(0.5f); goods.setCategoryId(43); list.add(goods); } int num = sqlSession.insert("goods.batchInsert", list); sqlSession.commit(); // 提交事物数据 long et = new Date().getTime(); System.out.println("num" + num); System.out.println( "执行时间 " + (et - st) + "毫秒");

批量插入数据的局限

  • 无法获得插入数据的id
  • 批量生成的SQL太长,可能会被服务器拒绝

八、MyBatis注解开发

注解可以替换原有的xml标签进行开发

注解

对应xml

说明

@Insert

新增sql

@Update

更新sql

@Delete

删除sql

@Select

查询sql

@Param

--

参数映射

@Results

结果映射

@Result

字段映射

新建DAO层 com/gu/dao/GoodsDao.java文件

package com.imooc.mybatis.dao; import com.imooc.mybatis.entity.Goods; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; 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})") // before = false在insert等语句之后执行 keyProperty主键 @SelectKey(statement = "select last_insert_id()", before = false, keyProperty = "goodsId", resultType = Integer.class) public int insert(Goods goods); @Results({ @Result(column="goods_id", property = "goodsId", id = true), @Result(column = "title", property = "title"), @Result(column = "current_price", property = "currentPrice") }) public List selectAll(); }

mybatis-config.xml文件创建相关映射

测试代码

@Test public void testSelectByPriceRange() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSession(); // session可以根据配置动态生成goodsDAO类 GoodsDAO goodsDAO = session.getMapper(GoodsDAO.class); List list = goodsDAO.selectByPriceRange(100f, 500f, 20); for(Goods goods: list) { System.out.println(goods.getTitle()); } }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 list = goodsDAO.selectAll(); System.out.println(list.size()); } catch (Exception e) { throw e; } finally { MyBatisUtils.closeSession(session); } }

相关内容

热门资讯

实测分享“友谊互动到底是不是挂... 实测分享“友谊互动到底是不是挂”@必胜开挂神器您好:友谊互动这款游戏可以开挂,确实是有挂的,需要了解...
玩家最新攻略“个旧麻将开挂神器... 玩家最新攻略“个旧麻将开挂神器”@太坑了果然有挂亲,个旧麻将这个游戏其实有挂的,确实是有挂的,需要了...
最新一款“天酷牛牛为什么一直输... 最新一款“天酷牛牛为什么一直输”@果然有透视挂亲.天酷牛牛这款游戏是可以开挂的,确实是有挂的,通过添...
重大消息“瓦力游戏真的有挂吗”... 重大消息“瓦力游戏真的有挂吗”@其实是有挂您好:瓦力游戏这款游戏可以开挂,确实是有挂的,需要了解加客...
今日重大消息“新圣游炸金花有挂... 今日重大消息“新圣游炸金花有挂辅助”@其实是有挂亲.新圣游炸金花这款游戏是可以开挂的,确实是有挂的,...