缓存机制

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持

  1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
  2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
  3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

Mybatis一级缓存测试

package com.spiritmark.test;

import menghan.domain.User;
import spiritmark.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test; /**
* @author gacl
* 测试一级缓存
*/
public class TestOneLevelCache { /*
* 一级缓存: 也就Session级的缓存(默认开启)
*/
@Test
public void testCache1() {
SqlSession session = MyBatisUtil.getSqlSession();
String statement = "me.gacl.mapping.userMapper.getUser";
User user = session.selectOne(statement, 1);
System.out.println(user); /*
* 一级缓存默认就会被使用
*/
user = session.selectOne(statement, 1);
System.out.println(user);
session.close();
/*
1. 必须是同一个Session,如果session对象已经close()过了就不可能用了
*/
session = MyBatisUtil.getSqlSession();
user = session.selectOne(statement, 1);
System.out.println(user); /*
2. 查询条件是一样的
*/
user = session.selectOne(statement, 2);
System.out.println(user); /*
3. 没有执行过session.clearCache()清理缓存
*/
//session.clearCache();
user = session.selectOne(statement, 2);
System.out.println(user); /*
4. 没有执行过增删改的操作(这些操作都会清理缓存)
*/
session.update("me.gacl.mapping.userMapper.updateUser",
new User(2, "user", 23));
user = session.selectOne(statement, 2);
System.out.println(user); }
}

Mybatis二级缓存测试

1、开启二级缓存,在userMapper.xml文件中添加如下配置

<mapper namespace="com.spiritmark.pojo.userMapper">
<!-- 开启二级缓存 -->
<cache/>

2、测试二级缓存

package com.spiritmark.test;

import spiritmark.gacl.domain.User;
import spiritmark.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test; /**
1. @author gacl
2. 测试二级缓存
*/
public class TestTwoLevelCache { /*
* 测试二级缓存
* 使用两个不同的SqlSession对象去执行相同查询条件的查询,第二次查询时不会再发送SQL语句,而是直接从缓存中取出数据
*/
@Test
public void testCache2() {
String statement = "me.gacl.mapping.userMapper.getUser";
SqlSessionFactory factory = MyBatisUtil.getSqlSessionFactory();
//开启两个不同的SqlSession
SqlSession session1 = factory.openSession();
SqlSession session2 = factory.openSession();
//使用二级缓存时,User类必须实现一个Serializable接口===> User implements Serializable
User user = session1.selectOne(statement, 1);
session1.commit();//不懂为啥,这个地方一定要提交事务之后二级缓存才会起作用
System.out.println("user="+user); //由于使用的是两个不同的SqlSession对象,所以即使查询条件相同,一级缓存也不会开启使用
user = session2.selectOne(statement, 1);
//session2.commit();
System.out.println("user2="+user);
}
}

二级缓存补充说明

  1. 映射语句文件中的所有select语句将会被缓存。
  2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。
  3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。
  4. 缓存会根据指定的时间间隔来刷新
  5. 缓存会存储1024个对象

cache标签常用属性:

<cache
eviction="FIFO" <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512" <!--最多缓存512个引用对象-->
readOnly="true"/> <!--只读-->

高级查询

表关系说明

  • 创建表
CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
create datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

对应的实体类

public class Order {
private Integer id;
private Long userId;
private String orderNumber;
private Date created;
private Date updated;
}

需求说明:

一对一查询

方法一:核心思想扩展Order对象,来完成映射

新建OrderUser实体类继承Order:

public class OrderUser extends Order {
private String userName;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
}

OrderMapper接口:

public interface OrderMapper {
OrderUser queryOrderUserByOrderNumber(@Param("number") String number);
}

配置OrderMapper:

<mapper namespace="com.lx.mybatis.dao.OrderMapper">
<select id="queryOrderUserByOrderNumber" resultType="com.zpc.mybatis.pojo.OrderUser">
select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number}
</select>
</mapper>

测试:

@Test
public void queryOrderUserByOrderNumber() throws Exception {
OrderUser orderUser = orderMapper.queryOrderUserByOrderNumber("201807010001");
System.out.println(orderUser);
}

方法二:面向对象的思想,在Order对象中添加User对象

在Order对象中添加User属性:

public class Order {
private Integer id;
private Long userId;
private String orderNumber;
private Date created;
private Date updated;
private User user;
}

接口:

/**
* 根据订单号查询订单用户的信息
* @param number
* @return
*/
public Order queryOrderWithUserByOrderNumber(@Param("number") String number);

使用resultType不能完成自动映射,需要手动完成结果集映射resultMap:

<resultMap id="OrderUserResultMap" type="com.LX.mybatis.pojo.Order" autoMapping="true">
<id column="id" property="id"/>
<!--association:完成子对象的映射-->
<!--property:子对象在父对象中的属性名-->
<!--javaType:子对象的java类型-->
<!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配-->
<association property="user" javaType="com.LX.mybatis.pojo.User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
</resultMap> <select id="queryOrderWithUserByOrderNumber" resultMap="OrderUserResultMap">
select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number}
</select>

测试:

@Test
public void queryOrderWithUserByOrderNumber() throws Exception {
Order order = orderMapper.queryOrderWithUserByOrderNumber("201807010001");
System.out.println(order.getUser());
}

一对多查询

一对多查询:查询订单,查询出下单人信息并且查询出订单详情。

Order类:

public class Order {
private Integer id;
private Long userId;
private String orderNumber;
private Date created;
private Date updated;
private User user;
private List<OrderDetail> detailList;
}
public class OrderDetail {
private Integer id;
private Integer orderId;
private Double totalPrice;
private Integer status;
}

接口:

/**
* 根据订单号查询订单用户的信息及订单详情
* @param number
* @return
*/
Order queryOrderWithUserAndDetailByOrderNumber(@Param("number") String number);

Mapper映射:

<resultMap id="OrderUserDetailResultMap" type="com.LX.mybatis.pojo.Order" autoMapping="true">
<id column="id" property="id"/>
<!--collection:定义子对象集合映射-->
<!--association:完成子对象的映射-->
<!--property:子对象在父对象中的属性名-->
<!--javaType:子对象的java类型-->
<!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配-->
<association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
<collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true">
<id column="id" property="id"/>
</collection>
</resultMap> <select id="queryOrderWithUserAndDetailByOrderNumber" resultMap="OrderUserDetailResultMap">
select * from tb_order o
left join tb_user u on o.user_id=u.id
left join tb_orderdetail od on o.id=od.order_id
where o.order_number = #{number}
</select>

测试:

@Test
public void queryOrderWithUserAndDetailByOrderNumber() throws Exception {
Order order = orderMapper.queryOrderWithUserAndDetailByOrderNumber("201807010001");
System.out.println(order.getUser());
System.out.println(order.getDetailList());
}

多对多查询

多对多查询:查询订单,查询出下单人信息并且查询出订单详情中的商品数据。

OrderDetail类

public class OrderDetail {
private Integer id;
private Integer orderId;
private Double totalPrice;
private Integer status;
private Item item;
} public class Item {
private Integer id;
private String itemName;
private Float itemPrice;
private String itemDetail;
}

接口:

/**
* 根据订单号查询订单用户的信息及订单详情及订单详情对应的商品信息
* @param number
* @return
*/
Order queryOrderWithUserAndDetailItemByOrderNumber(@Param("number") String number);

Mapper配置:

<resultMap id="OrderUserDetailItemResultMap" type="com.LX.mybatis.pojo.Order" autoMapping="true">
<id column="id" property="id"/>
<association property="user" javaType="com.LX.mybatis.pojo.User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
<collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true">
<id column="detail_id" property="id"/>
<association property="item" javaType="com.zpc.mybatis.pojo.Item" autoMapping="true">
<id column="item_id" property="id"/>
</association>
</collection>
</resultMap> <select id="queryOrderWithUserAndDetailItemByOrderNumber" resultMap="OrderUserDetailItemResultMap">
select * ,od.id as detail_id from tb_order o
left join tb_user u on o.user_id=u.id
left join tb_orderdetail od on o.id=od.order_id
left join tb_item i on od.item_id=i.id
where o.order_number = #{number}
</select>

测试:

@Test
public void queryOrderWithUserAndDetailItemByOrderNumber() throws Exception {
Order order = orderMapper.queryOrderWithUserAndDetailItemByOrderNumber("201807010001");
System.out.println(order);
System.out.println(order.getUser());
System.out.println(order.getDetailList());
}

SQL语句如下 :

CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
create datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO tb_order VALUES (‘1’, ‘2’, ‘201807010001’, ‘2018-07-01 19:38:35’, ‘2018-07-01 19:38:40’); CREATE TABLE tb_item (
id int(11) NOT NULL,
itemName varchar(255) DEFAULT NULL,
itemPrice decimal(10,2) DEFAULT NULL,
itemDetail varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO tb_item VALUES (‘1’, ‘袜子’, ‘29.90’, ‘香香的袜子’);
INSERT INTO tb_item VALUES (‘2’, ‘套子’, ‘99.99’, ‘冈本001’); CREATE TABLE tb_orderdetail (
id int(11) NOT NULL AUTO_INCREMENT,
order_id int(11) DEFAULT NULL,
total_price decimal(10,0) DEFAULT NULL,
item_id int(11) DEFAULT NULL,
status int(10) unsigned zerofill DEFAULT NULL COMMENT ‘0成功非0失败’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO tb_orderdetail VALUES (‘1’, ‘1’, ‘10000’, ‘1’, ‘0000000001’);
INSERT INTO tb_orderdetail VALUES (‘2’, ‘1’, ‘2000’, ‘2’, ‘0000000000’);

时间过的很快 ! 快S2结业了 没时间 给大家更新了 希望大家记住

路在自己脚下,没有人可以决定你前进的方向。 加油!

最新文章

  1. Leetcode 99: Recovery binary search tree 总算明白了算法, 把代码写清楚, 让错误无处可藏.
  2. 入侵本地Mac OS X的详细过程 转自https://yq.aliyun.com/articles/22459?spm=5176.100239.blogcont24250.10.CfBYE9
  3. 字符串转Json对象
  4. 357. Count Numbers with Unique Digits
  5. DWZ(JUI) 教程 中如何整合第三方jQuery插件
  6. git stash 暂存当前修改
  7. 百度地图api的实现
  8. Thinkphp twig
  9. UVA 322 ships (POJ 1138)
  10. linux 软连接 硬连接
  11. Python 处理文件
  12. Struts2文件的下载
  13. Redis缓存数据之简单逻辑
  14. windows c++程序移植到linux的要点
  15. 小程序——Tab切换
  16. java常见命名规则
  17. window apidoc的安装和使用
  18. Hadoop中 Unable to load native-hadoop library for your platform... using builtin-java classes where applicable问题解决
  19. c#基础学习(0724)之可变参数、ref和out
  20. mfc 类对象的引用

热门文章

  1. 微课制作软件Camtasia中如何添加并编辑字幕?
  2. MAC系统网页链接如何下载
  3. Xcode6在ios7上编译framework报错
  4. Python学习系列之列表(十一)
  5. O - Matching 题解(状压dp)
  6. Java基础教程——Scanner类
  7. C# WinForm UDP 发送和接收消息
  8. 删除list列表中的某一个元素的多种方法
  9. 最佳置换算法OPT
  10. 一万字详解 Redis Cluster Gossip 协议