持久层之 MyBatis: 第三篇 :缓存 And 高级查询
生活随笔
收集整理的這篇文章主要介紹了
持久层之 MyBatis: 第三篇 :缓存 And 高级查询
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
MyBatis入門到精通3
- 緩存機制
- Mybatis一級緩存測試
- Mybatis二級緩存測試
- 高級查詢
- 表關系說明
- 一對一查詢
- 一對多查詢
- 多對多查詢
緩存機制
正如大多數持久層框架一樣,MyBatis 同樣提供了一級緩存和二級緩存的支持
- 一級緩存: 基于PerpetualCache 的 HashMap本地緩存,其存儲作用域為 Session,當 Session flush 或 close 之后,該Session中的所有 Cache 就將清空。
- 二級緩存與一級緩存其機制相同,默認也是采用 PerpetualCache,HashMap存儲,不同在于其存儲作用域為 Mapper(Namespace),并且可自定義存儲源,如 Ehcache。
- 對于緩存數據更新機制,當某一個作用域(一級緩存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);
}
}
二級緩存補充說明
- 映射語句文件中的所有select語句將會被緩存。
- 映射語句文件中的所有insert,update和delete語句會刷新緩存。
- 緩存會使用Least Recently Used(LRU,最近最少使用的)算法來收回。
- 緩存會根據指定的時間間隔來刷新
- 緩存會存儲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結業了 沒時間 給大家更新了 希望大家記住
路在自己腳下,沒有人可以決定你前進的方向。 加油!
總結
以上是生活随笔為你收集整理的持久层之 MyBatis: 第三篇 :缓存 And 高级查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 063——VUE中vue-router之
- 下一篇: 大v用户数据统计分析