一级缓存是SqlSession级别的,通过同一个lSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
一级缓存失效的四种情况:
<?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>com.hu</groupId>
<artifactId>RDmybatis07</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--Lombok在编译时不使用-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
jdbc.username=root
jdbc.password=123456
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--MyBatis 核 心 配 置 文 件 中 , 标 签 的 顺 序 :
properties?,settings?,typeAliases?,typeHandlers?,
objectFactory?,objectWrapperFactory?,reflectorFactory?,
plugins?,environments?,databaseIdProvider?,mappers?
-->
<!--引入properties文件-->
<properties resource="jdbc.properties"/>
<settings>
<!--开启驼峰转换功能-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。
默认时是flase
-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--开启时,任一方法的调用都会加载该对象的所有延迟加载属性。
否则,每个延迟加载属性会按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!--设置类型别名-->
<typeAliases>
<!--
typeAlias:设置某个类型的别名属性:
type:设置需要设置别名的类型
alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名
且不区分大小写
-->
<!--
<typeAlias type="com.softeem.mybatis.pojo.User"></typeAlias>
通过typeAlias配置单个的类型别名
通过package属性,将包下所有的类型设置默认的类型别名,即类名且不区分大小写
-->
<!--以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写-->
<package name="com.hu.pojo"/>
</typeAliases>
<!--
environments:配置多个连接数据库的环境属性:
default:设置默认使用的环境的id
transactionManager:设置事务管理方式属性:
type="JDBC|MANAGED"
JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,
事务的提交或回滚需要手动处理
MANAGED:被管理,例如Spring
dataSource:配置数据源属性:
type:设置数据源的类型type="POOLED|UNPOOLED|JNDI"
POOLED:表示使用数据库连接池缓存数据库连接
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据源
-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<!--
<mapper resource="mappers/UserMapper.xml"/>
配置mapper文件,有可能有很大xml,所以直接配置一个包下面的
和别名一样
以包为单位引入映射文件要求:
1、mapper接口所在的包要和映射文件所在的包一致
2、mapper接口要和映射文件的名字一致
-->
<package name="com.hu.mapper"/>
</mappers>
</configuration>
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES (1, '开发部');
INSERT INTO `dept` VALUES (2, '市场部');
INSERT INTO `dept` VALUES (3, '财务部');
INSERT INTO `dept` VALUES (4, '销售部');
INSERT INTO `dept` VALUES (5, '烟酒部');
INSERT INTO `dept` VALUES (6, '小卖部');
-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`salary` double NULL DEFAULT NULL,
`join_date` date NULL DEFAULT NULL,
`dept_id` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `dept_id`(`dept_id`) USING BTREE,
CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES (1, '孙悟空', '男', 7200, '2013-02-24', 5);
INSERT INTO `emp` VALUES (3, '唐僧', '男', 9000, '2008-08-08', 2);
INSERT INTO `emp` VALUES (4, '白骨精', '女', 5000, '2015-10-07', 3);
INSERT INTO `emp` VALUES (5, '蜘蛛精', '女', 4500, '2011-03-14', 1);
INSERT INTO `emp` VALUES (6, '沙僧', '男', 7200, '2013-12-05', 1);
INSERT INTO `emp` VALUES (7, '白龙马', '男', 7000, '2013-12-05', 1);
INSERT INTO `emp` VALUES (8, '小明', '女', 2000, '2020-01-01', 2);
INSERT INTO `emp` VALUES (9, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (11, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (15, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (16, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (17, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (18, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (19, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (20, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (21, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (22, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (23, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (24, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (25, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (26, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (27, '小明', '女', 2000, '2020-01-01', 1);
INSERT INTO `emp` VALUES (28, '小灰灰1', '男', 3100, '2022-08-30', 5);
INSERT INTO `emp` VALUES (33, '小灰灰3', '男', 3300, '2022-08-30', 5);
INSERT INTO `emp` VALUES (34, '张三', '男', 1000, '2022-10-05', 1);
代码讲解:
1.在EmpMapper中添加一个方法
public interface EmpMapper {
Emp findEmpById(Integer id);
}
2.配置对应的xml文件,EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hu.mapper.EmpMapper">
<resultMap id="empMap" type="emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="dept_id" property="deptId"/>
<result column="salary" property="salary"/>
<result column="join_date" property="joinDate"/>
<result column="gender" property="gender"/>
</resultMap>
<select id="findEmpById" resultMap="empMap">
select * from emp where id = #{id}
</select>
</mapper>
3.测试
public class EmpTest {
SqlSession sqlSession = null;
@Before
public void init() throws IOException {
// 1. 先读取我们所需要的配置类对象
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2. 创建我们所需要的SqlSessionFactoryBuilder来创建我们所需要的SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 3. 获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 4. 通过工厂对象来获取SqlSession对象 , 并且设置为自动提交
//sqlSession = sqlSessionFactory.openSession();
sqlSession = sqlSessionFactory.openSession(true);
}
@Test
public void test() {
// 1. 通过SqlSession对象来获取Mapper对象
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 2. 通过Mapper对象来执行查询操作
Emp emp = mapper.findEmpById(1);
System.out.println(emp);
Emp emp2 = mapper.findEmpById(1);
System.out.println(emp2);
}
}
测试结果如图:
可以看到,我们在执行同一个查询语句的时候,第二次查询的时候没有显示执行sql的语句,而是直接显示结果,这表示,我们是从缓存中直接读取数据,提高我们的查询速度.
@Test
public void test() {
// 1. 通过SqlSession对象来获取Mapper对象
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 2. 通过Mapper对象来执行查询操作
Emp emp = mapper.findEmpById(1);
System.out.println(emp);
Emp emp2 = mapper.findEmpById(2);
System.out.println(emp2);
}
测试结果如下:
由此可知,当我们查询条件不同,我们的一级缓存会失效.
@Test
public void test() {
// 1. 通过SqlSession对象来获取Mapper对象
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 2. 通过Mapper对象来执行查询操作
Emp emp = mapper.findEmpById(1);
System.out.println(emp);
sqlSession.clearCache();
Emp emp2 = mapper.findEmpById(1);
System.out.println(emp2);
}
由此可见,当我们主动清除缓存的时候,一级缓存也会失效
在EmpMapper中添加一个方法
public interface EmpMapper {
Emp findEmpById(Integer id);
int deleteEmpById(Integer id);
}
编写对应的xm文件EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hu.mapper.EmpMapper">
<resultMap id="empMap" type="emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="dept_id" property="deptId"/>
<result column="salary" property="salary"/>
<result column="join_date" property="joinDate"/>
<result column="gender" property="gender"/>
</resultMap>
<select id="findEmpById" resultMap="empMap">
select * from emp where id = #{id}
</select>
<delete id="deleteEmpById">
delete from emp where id = #{id}
</delete>
</mapper>
EmpTest.java
@Test
public void test() {
// 1. 通过SqlSession对象来获取Mapper对象
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 2. 通过Mapper对象来执行查询操作
Emp emp = mapper.findEmpById(1);
System.out.println(emp);
mapper.deleteEmpById(2);
Emp emp2 = mapper.findEmpById(1);
System.out.println(emp2);
}
由此可见,当我们在俩次查询语句中进行了增删改操作,也会导致一级缓存失效
public interface EmpMapper {
Emp findEmpById(Integer id);
int deleteEmpById(Integer id);
Emp findEmpByName(String name);
}
编写对应的EmpMapper.xml
<select id="findEmpByName" resultMap="empMap">
select * from emp where name = #{name}
</select>
测试类EmpTest
@Test
public void test() {
// 1. 通过SqlSession对象来获取Mapper对象
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 2. 通过Mapper对象来执行查询操作
Emp emp = mapper.findEmpById(1);
System.out.println(emp);
mapper.deleteEmpById(2);
Emp emp2 = mapper.findEmpByName("孙悟空");
System.out.println(emp2);
}
测试结果如下:
如图我们可以看出,当我们查询同一个对象,但是是不同的条件时,一级缓存也会失效.
public class EmpTest {
SqlSession sqlSession1 = null;
SqlSession sqlSession2 = null;
@Before
public void init() throws IOException {
// 1. 先读取我们所需要的配置类对象
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2. 创建我们所需要的SqlSessionFactoryBuilder来创建我们所需要的SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 3. 获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 4. 通过工厂对象来获取SqlSession对象 , 并且设置为自动提交
//sqlSession = sqlSessionFactory.openSession();
sqlSession1 = sqlSessionFactory.openSession(true);
sqlSession2 = sqlSessionFactory.openSession(true);
}
@Test
public void test() {
// 1. 通过SqlSession对象来获取Mapper对象
EmpMapper mapper = sqlSession1.getMapper(EmpMapper.class);
// 2. 通过Mapper对象来执行查询操作
Emp emp = mapper.findEmpById(1);
System.out.println(emp);
mapper.deleteEmpById(2);
System.out.println("_____________________________");
EmpMapper mapper1 = sqlSession2.getMapper(EmpMapper.class);
Emp emp2 = mapper1.findEmpById(1);
System.out.println(emp2);
}
}
运行结果如下:
由此可见,但我们使用俩个SqlSession时,俩个SqlSession对应着不同的一级缓存.