一、延迟加载

resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
  延迟加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading

设置项 描述 允许值 默认值
lazyLoadingEnabled 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。 true \ false false
aggressiveLazyLoading 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 true \ false true
//例如
<settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>
</settings>

场合:
当只有部分记录需要关联查询其它信息时,此时可按需延迟加载,需要关联查询时再向数据库发出sql,以提高数据库性能。
当全部需要关联查询信息时,此时不用延迟加载,直接将关联查询信息全部返回即可,可使用resultType或resultMap完成映射。

二、查询缓存

Mybatis提供查询缓存,用于减轻数据压力,提高数据库压力。
  Mybatis提供一级缓存和二级缓存。
  
  在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于缓存数据。
  不同的SqlSession之间的缓存数据区域是互相不影响的。
  Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
  Mybatis二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。

1、一级缓存


  第一次发起查询,先去找缓存中是否有id为1的用户信息,如果没有,从数据库中查询用户信息。
  得到用户信息,将用户信息存储到一级缓存中。
  第二次发起查询用户id为1的用户信息,先去缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
  如果SqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存。目的是为了让缓存中存储的是最新的信息,避免脏读。
  Mybatis默认支持一级缓存,不需要在配置文件中配置。
  Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象。
  应用场景:
  

2、二级缓存


  SqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
  SqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
  二级缓存区域是根据mapper的namespace划分的,相同namespace的mapper查询数据放在同一个区域,如果使用mapper代理方法每个mapper的namespace都不同,此时可以理解为二级缓存区域是根据mapper划分。
每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存。
  Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
  sqlSession执行insert、update、delete等操作commit提交后会清空缓存区域。
  开启二级缓存:
  在核心配置文件SqlMapConfig.xml中加入

    <setting name="cacheEnabled" value="true"/>
描述 允许值 默认值
cacheEnabled对在此配置文件下的所有cache 进行全局性开/关设置。 true false true

要在你的Mapper映射文件中添加一行: ,表示此mapper

开启二级缓存。

二级缓存需要查询结果映射的pojo对象实现java.io.Serializable接口实现序列化和反序列化操作,注意如果存在父类、成员pojo都需要实现序列化接口。
  为了将缓存数据取出执行反序列化,因为二级缓存存储介质多种多样,不一定在内存。

禁用二级缓存:

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

刷新缓存(就是清空缓存):
  设置statement配置中的flushCache=“true” 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

应用场景:
  对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
  局限性:
  mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。

案例


UserMapper.java

package com.xbj.mapper;
import com.xbj.po.TUser;
import java.util.List;
/*** 延迟加载*/
public interface UserMapper {//延迟加载List<TUser> userIncludeOrder();TUser findUserById(Integer id);List<TUser> findAll();void deleteById(Integer id);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.xbj.mapper.UserMapper"><!--开启二级缓存--><cache /><!--SQL片段的引用--><sql id="baseSql">SELECT * from t_user</sql><!--延迟加载--><resultMap id="userInfos" type="TUser" autoMapping="true"><id property="id" column="id"/><collection property="tOrders" ofType="TOrder" select="findorderByUid"  column="id"/></resultMap><select id="findorderByUid" resultType="TOrder" parameterType="int">SELECT  * from t_order where uid=#{id}</select><select id="userIncludeOrder" resultMap="userInfos">SELECT * from t_user</select><select id="findUserById" parameterType="int" resultType="TUser">SELECT * FROM t_user where id=#{id}</select><select id="findAll" resultType="TUser">SELECT * from t_user</select><delete id="deleteById" parameterType="int" >DELETE  from t_user WHERE id=#{id}</delete></mapper>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>groupId</groupId><artifactId>dome02</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.14</version></dependency></dependencies>
</project>

sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><!--允许延迟加载--><setting name="lazyLoadingEnabled" value="true"/></settings><typeAliases><package name="com.xbj.po"  /></typeAliases><!--数据源的配置--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/user"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--对象的操作--><mappers><!--<mapper resource="com/com.xbj/mapper/UserMapper.xml"/>--><!--<mapper url="file:///D:\projects\javaprojects\620\Demo02\src\main\resources\com\com.xbj\mapper\UserMapper.xml" />--><!--<mapper class="com.com.xbj.mapper.UserMapper" />--><package name="com.xbj.mapper" /></mappers>
</configuration>

log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

TOrder.java

package com.xbj.po;import java.io.Serializable;
import java.util.List;/*** @Author:晓宇码匠* @Date:2019/6/21 0021*/
public class TUser implements Serializable {private int id;private String username;private String password;private Integer age;private List<TOrder> tOrders;public List<TOrder> gettOrders() {return tOrders;}public void settOrders(List<TOrder> tOrders) {this.tOrders = tOrders;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;TUser tUser = (TUser) o;if (id != tUser.id) return false;if (username != null ? !username.equals(tUser.username) : tUser.username != null) return false;if (password != null ? !password.equals(tUser.password) : tUser.password != null) return false;if (age != null ? !age.equals(tUser.age) : tUser.age != null) return false;return true;}@Overridepublic int hashCode() {int result = id;result = 31 * result + (username != null ? username.hashCode() : 0);result = 31 * result + (password != null ? password.hashCode() : 0);result = 31 * result + (age != null ? age.hashCode() : 0);return result;}@Overridepublic String toString() {return "TUser{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +'}';}
}

TUser.java

package com.xbj.po;import java.io.Serializable;
import java.util.List;/*** @Author:晓宇码匠* @Date:2019/6/21 0021*/
public class TUser implements Serializable {private int id;private String username;private String password;private Integer age;private List<TOrder> tOrders;public List<TOrder> gettOrders() {return tOrders;}public void settOrders(List<TOrder> tOrders) {this.tOrders = tOrders;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;TUser tUser = (TUser) o;if (id != tUser.id) return false;if (username != null ? !username.equals(tUser.username) : tUser.username != null) return false;if (password != null ? !password.equals(tUser.password) : tUser.password != null) return false;if (age != null ? !age.equals(tUser.age) : tUser.age != null) return false;return true;}@Overridepublic int hashCode() {int result = id;result = 31 * result + (username != null ? username.hashCode() : 0);result = 31 * result + (password != null ? password.hashCode() : 0);result = 31 * result + (age != null ? age.hashCode() : 0);return result;}@Overridepublic String toString() {return "TUser{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +'}';}
}

test.java

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import com.xbj.mapper.UserMapper;
import com.xbj.po.TUser;import java.io.IOException;
import java.io.InputStream;
import java.util.List;/*** @Author:晓宇码匠* @Date:2019/6/21 0021*/
public class test {private UserMapper userMapper;@Beforepublic void init() throws IOException {InputStream is= Resources.getResourceAsStream("sqlMapConfig.xml");userMapper=new SqlSessionFactoryBuilder().build(is).openSession(true).getMapper(UserMapper.class);}//测试延迟加载@Testpublic void t1(){List<TUser> infos=userMapper.userIncludeOrder();System.out.println(infos);}//测试一级缓存@Testpublic void t2(){TUser user1=userMapper.findUserById(1);TUser user2=userMapper.findUserById(1);}/*在进行增、改、删操作的时候会清空缓存*/@Testpublic void t3(){userMapper.findAll();userMapper.deleteById(4);userMapper.findAll();}}

Test02.java

import com.xbj.mapper.UserMapper;
import com.xbj.po.TUser;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;public class Test02 {private SqlSessionFactory factory;private UserMapper userMapper;private UserMapper userMapper2;@Beforepublic void init() throws IOException {InputStream is= Resources.getResourceAsStream("sqlMapConfig.xml");factory=new SqlSessionFactoryBuilder().build(is);userMapper=factory.openSession(true).getMapper(UserMapper.class);userMapper2=factory.openSession(true).getMapper(UserMapper.class);}/*测试在不同的mapper会话中,是访问不同的缓存区*/@Testpublic void t1(){TUser user1=userMapper.findUserById(1);TUser user2=userMapper2.findUserById(1);}/*在进行增、改、删操作的时候会清空缓存*/@Testpublic void t2(){userMapper.findAll();userMapper.deleteById(4);userMapper.findAll();}/*测试二级缓存的时候,需要将第一个查询操作先关闭,否则程序不会进入缓存里面查找数据*/@Testpublic void t3(){SqlSession sqlSession1=factory.openSession(true);SqlSession sqlSession2=factory.openSession(true);sqlSession1.selectOne("findUserById",1);sqlSession1.close();  //第一个人 调用后 会话结束 写入缓存sqlSession2.selectOne("findUserById",1);}
}

sql.sql

/*
Navicat MySQL Data TransferSource Server         : Mysql
Source Server Version : 50717
Source Host           : localhost:3306
Source Database       : userTarget Server Type    : MYSQL
Target Server Version : 50717
File Encoding         : 65001Date: 2019-06-21 15:06:09
*/SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for t_item
-- ----------------------------
DROP TABLE IF EXISTS `t_item`;
CREATE TABLE `t_item` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(200) NOT NULL,`detail` varchar(200) DEFAULT NULL,`price` float(10,2) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_item
-- ----------------------------
INSERT INTO `t_item` VALUES ('1', '苹果', '真好吃', '6.00');
INSERT INTO `t_item` VALUES ('2', '橘子', '淮南橘子', '3.00');
INSERT INTO `t_item` VALUES ('3', '香蕉', '海南香蕉,香蕉中的战斗蕉', '2.00');
INSERT INTO `t_item` VALUES ('4', '芒果', '泰国芒果', '11.00');-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (`id` int(11) NOT NULL AUTO_INCREMENT,`uid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `uid` (`uid`),CONSTRAINT `t_order_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `t_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_order
-- ----------------------------
INSERT INTO `t_order` VALUES ('1', '1');
INSERT INTO `t_order` VALUES ('2', '1');
INSERT INTO `t_order` VALUES ('3', '1');
INSERT INTO `t_order` VALUES ('4', '2');
INSERT INTO `t_order` VALUES ('5', '3');-- ----------------------------
-- Table structure for t_order_detail
-- ----------------------------
DROP TABLE IF EXISTS `t_order_detail`;
CREATE TABLE `t_order_detail` (`id` int(11) NOT NULL AUTO_INCREMENT,`oid` int(11) DEFAULT NULL,`item_id` int(11) DEFAULT NULL,`count` float(8,2) DEFAULT NULL,PRIMARY KEY (`id`),KEY `oid` (`oid`),KEY `item_id` (`item_id`),CONSTRAINT `t_order_detail_ibfk_1` FOREIGN KEY (`oid`) REFERENCES `t_order` (`id`),CONSTRAINT `t_order_detail_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `t_item` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_order_detail
-- ----------------------------
INSERT INTO `t_order_detail` VALUES ('1', '1', '1', '2.00');
INSERT INTO `t_order_detail` VALUES ('2', '1', '2', '2.00');
INSERT INTO `t_order_detail` VALUES ('3', '2', '3', '2.00');
INSERT INTO `t_order_detail` VALUES ('4', '2', '4', '2.00');
INSERT INTO `t_order_detail` VALUES ('5', '3', '1', '2.00');
INSERT INTO `t_order_detail` VALUES ('6', '3', '1', '2.00');
INSERT INTO `t_order_detail` VALUES ('7', '4', '2', '2.00');
INSERT INTO `t_order_detail` VALUES ('8', '4', '2', '2.00');
INSERT INTO `t_order_detail` VALUES ('9', '5', '1', '2.00');
INSERT INTO `t_order_detail` VALUES ('10', '1', '4', '2.00');-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(200) NOT NULL,`password` varchar(200) NOT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES ('1', 'tom', 'ok', '33');
INSERT INTO `t_user` VALUES ('2', 'lucy', 'ok', '43');
INSERT INTO `t_user` VALUES ('3', 'jack', 'ok', '53');

Mybatis延迟加载和查询缓存相关推荐

  1. Mybatis高级应用 查询缓存

    mybatis提供了查询缓存功能,用于减轻数据压力,提高数据库性能.mybatis提供了一级缓存和二级缓存,如下图所示: 从上图可以看出: 一级缓存是存在于一个sqlSession中的,而sqlSes ...

  2. MyBatis 延迟加载,一级缓存(sqlsession级别)、二级缓存(mapper级别)设置

    什么是延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再去加载关联信息 ...

  3. MyBatis 延迟加载,一级缓存,二级缓存设置

    什么是延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再去加载关联信息 ...

  4. mybatis中的查询缓存

    转载自:https://www.cnblogs.com/zhangzongle/p/6211285.html 查询缓存 Mybatis提供查询缓存,用于减轻数据压力,提高数据库压力. Mybatis提 ...

  5. 【MyBatis框架】查询缓存-二级缓存-整合ehcache

    mybatis整合ehcache ehcache是一个分布式缓存框架. 1.分布缓存 我们系统为了提高系统并发,性能.一般对系统进行分布式部署(集群部署方式) 如图 不使用分布缓存,缓存的数据在各各服 ...

  6. 【MyBatis框架】查询缓存-一级缓存原理

    查询缓存 1.什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 缓存模式图如图 一级缓存是SqlSession级别的缓存.在操作 ...

  7. 【MyBatis框架】查询缓存-二级缓存原理

    二级缓存原理 1.原理 首先看图 首先开启mybatis的二级缓存. sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中. 如果SqlSession3去执行 ...

  8. 手写自己的MyBatis框架-支持查询缓存

    定义了一个CachingExecutor , 当全局配置中的cacheEnabled=true 时,Configuration 的newExecutor()方法会对SimpleExecutor 进行装 ...

  9. MyBatis 相同事物查询缓存问题

    http://www.tuicool.com/articles/mmUbEf 转载于:https://www.cnblogs.com/daxin/p/5186432.html

最新文章

  1. ubuntu系统无法ssh登录--安装openssh
  2. 个性化资源管理器软件Q-dir_6.36(附安装包)
  3. JavaScript学习笔记:语句
  4. 云服务器cpu系列,云服务器cpu系列
  5. 编写批处理文件编译.Net工程
  6. js中判断数组中是否含有某个字符串方法
  7. 南开大学提出新物体分割评价指标,相比经典指标错误率降低 69.23%
  8. zabbix-proxy+cacti+nagios基本安装配置
  9. Python-OpenCV学习(十)用GrabCUt算法进行图片前景的提取
  10. 计算机科学渗透信息论的思想,认知主义理论
  11. redis集群搭建管理入门
  12. composition api在项目中的使用总结
  13. win7计算机系统还原,win7怎么系统还原 还原步骤详解
  14. 核心单词Word List 46
  15. 基于android的教育机构家校通系统app
  16. serverless-OpenWhisk安装
  17. 金沙滩51单片机74HC138 三八译码器的应用
  18. vue 流星的样式和流光canvas
  19. imagin.vmem取证
  20. C++ 实现tring字符串trim函数和split函数

热门文章

  1. 996算什么,955能做出996的活,那才叫牛!
  2. 2015年份大众点评数据统计分析 大众点评数据下载
  3. 仓库管理软件哪个好?一键解决仓库出入库、管理库存,选这些软件
  4. 【逆向】【Android微信】加密数据库踩坑
  5. Camtasia Studio录制视频总是有杂音的处理方法
  6. plsql登录报错:ORA-27101: shared memory realm does not exist 错误的处理
  7. SQL 怎么用cmd执行.sql文件
  8. 怎么在CAD编辑软件中批量打印图纸
  9. 如何用谷歌(Chorme) 浏览器查看请求头(header)、响应头?
  10. python+selenium的一个小蜘蛛