第4章 MyBatis的关联映射和缓存机制
目录/Contents
- 第4章 MyBatis的关联映射和缓存机制
- 学习目标
- 了解数据表之间的三种关联关系
- 了解对象之间的三种关系
- 熟悉关联关系中的嵌套查询和嵌套结果
- 掌握一对一关联映射
- 掌握一对多关联映射
- 掌握多对多关联映射
- 熟悉Mybatis的缓存机制
- 学习内容
- 1 关联映射概述
- 1.1 关联映射关系
- 1.1.1 一对一关系
- 1.1.2 一对多关系
- 1.1.3 多对多关系
- 1.2 Java对象如何描述事物之间的关系
- 1.3 Java对象关联映射关系
- 1.3.1 一对一
- 1.3.2 一对多
- 1.3.3 多对多
- 2 一对一查询
- 2.1 \<association>元素
- 2.2 \<association>元素属性
- 2.3 \<association>元素的配置方式
- 2.4 一对一查询案例
- 2.4.1 创建数据表
- 2.4.2 持久化类IDCard类
- 2.4.3 持久化类Person类
- 2.4.4 编写IdCardMapper.xml文件
- 2.4.5 编写PersonMapper.xml文件
- 2.4.6 引入映射文件
- 2.4.7 编写测试类
- 2.5 多学一招:MyBatis延迟加载的配置
- 3 一对多查询
- 3.1 用户与订单关联关系图
- 3.2 \<collection>元素
- 3.3 \<collection>元素的配置方式
- 3.3.1 a.嵌套查询方式
- 3.3.2 b.嵌套查询方式
- 3.4 一对多查询案例
- 3.4.1 创建数据库
- 3.4.2 创建持久化类Orders
- 3.4.3 创建持久化类Users
- 3.4.4 创建用户实体映射文件UsersMapper.xml
- 3.4.5 在核心配置文件mybatis-config.xml中
- 3.4.6 在测试类MyBatisTest中
- 4 多对多查询
- 4.1 订单和商品多对多关系图
- 4.2 多对多查询案例
- 4.2.1 STEP 01
- 4.2.2 STEP 02
- 4.2.3 STEP 03
- 4.2.4 STEP 04
- 4.2.5 STEP 05
- 4.2.6 STEP 06
- 4.2.7 STEP 07
- 5 MyBatis缓存机制
- 5.1 一级缓存
- 5.1.1 MyBatis的一级缓存级别
- 5.1.2 举例说明MyBatis的一级缓存级别
- 5.1.3 案例的查询过程
- 5.1.4 建立数据库
- 5.1.5 创建持久化类Book
- 5.1.6 创建图书映射文件BookMapper.xml
- 5.1.7 在核心配置文件mybatis-config.xml中的<mappers>标签下
- 5.1.8 由于需要通过log4j日志组件查看一级缓存的工作状态
- 5.1.9 创建log4j.properties文件
- 5.1.10 在测试类MyBatisTest中
- 5.2 二级缓存
- 5.2.1使用二级缓存的好处
- 5.2.2 MyBatis二级缓存的执行过程
- 5.2.3 MyBatis二级缓存的执行过程图解
- 5.2.4 二级缓存与一级缓存的不同点
- 5.2.4.1 a.开启二级缓存的全局配置
- 5.2.4.1 b.开启当前Mapper的namespace下的二级缓存
- 5.2.5 默认状态的二级缓存可实现的功能
- 5.2.6 \<cache>元素的属性
- 5.2.7 修改映射文件BookMapper.xml
- 5.2.8 在测试类MyBatisTest中
- 5.2.9 执行MyBatisTest测试类的findBookByIdTest3()方法
- 5.2.10 对MyBatis二级缓存的应用案例的运行结果分析
- 5.2.11 多个SqlSession在同一个Mapper中执行
- 5.2.12 多学一招:Cache Hit Ratio(缓存命中率)
- 6 案例:商品的类别
- 6.1 商品表(product)商品类别表(category)详情
- 6.2 案例具体要求
- 6.3 项目搭建
- 6.4 数据库准备
- 6.5 POJO类准备1
- 6.6 POJO类准备2
- 6.7 编写映射文件
- 6.8 修改mybatis-config.xml核心配置文件
- 6.9 编写测试方法
- 6.10 查看运行结果
第4章 MyBatis的关联映射和缓存机制
学习目标
了解数据表之间的三种关联关系
了解对象之间的三种关系
熟悉关联关系中的嵌套查询和嵌套结果
掌握一对一关联映射
掌握一对多关联映射
掌握多对多关联映射
熟悉Mybatis的缓存机制
学习内容
1 关联映射概述
1.1 关联映射关系
在关系型数据库中,表与表之间存在着三种关联映射关系,分别为一对一关系、一对多关系和多对多关系。
1.1.1 一对一关系
一个数据表中的一条记录最多可以和另一个数据表中的一条记录相关。例如,现实生活中学生与校园卡就属于一对一的关系,一个学生只能拥有一张校园卡,一张校园卡只能属于一个学生。
1.1.2 一对多关系
主键数据表中的一条记录可以和另外一个数据表的多条记录相关。但另外一个数据表中的记录只能与主键数据表中的某一条记录相关。例如,现实中班级与学生的关系就属于一对多的关系,一个班级可以有很多学生,但一个学生只能属于一个班级。
1.1.3 多对多关系
一个数据表中的一条记录可以与另外一个数据表任意数量的记录相关,另外一个数据表中的一条记录也可以与本数据表中任意数量的记录相关。例如,现实中学生与教师属于多对多的关系,一名学生可以由多名教师授课,一名教师可以为多名学生授课。
1.2 Java对象如何描述事物之间的关系
1.3 Java对象关联映射关系
Java对象描述数据之间的关联映射关系有三种,分别是一对一、一对多和多对多。
1.3.1 一对一
就是在本类中定义与之关联的类的对象作为属性,例如,A类中定义B类对象b作为属性,在B类中定义A类对象a作为属性。
1.3.2 一对多
就是一个A类对象对应多个B类对象的情况,例如,定义在A类中,定义一个B类对象的集合作为A类的属性;在B类中,定义A类对象a作为B类的属性。
1.3.3 多对多
在两个相互关联的类中,都可以定义多个与之关联的类的对象。例如,在A类中定义B类类型的集合作为属性,在B类中定义A类类型的集合作为属性。
2 一对一查询
2.1 <association>元素
在现实生活中,一对一关联关系是十分常见的。例如,一个人只能有一个身份证,同时一个身份证也只会对应一个人。人与身份证之间的关联关系如图。
在MyBatis中,通过 <association>元素来处理一对一关联关系。<association>元素提供了一系列属性用于维护数据表之间的关系。
2.2 <association>元素属性
2.3 <association>元素的配置方式
<association>元素是<resultMap>元素的子元素,它有两种配置方式,嵌套查询方式和嵌套结果方式,下面对这两种配置方式分别进行介绍。
a.嵌套查询方式
嵌套查询是指通过执行另外一条SQL映射语句来返回预期的复杂类型。
<association property="card" column="card_id" javaType="com.itheima.pojo.IdCard" select="com.itheima.mapper.IdCardMapper.findCodeById" />
b.嵌套结果方式
嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集。
<association property="card" javaType="com.itheima.pojo.IdCard"><id property="id" column="card_id" /><result property="code" column="code" />
</association>
2.4 一对一查询案例
2.4.1 创建数据表
在mybatis数据库中分别创建名为tb_idcard的身份证数据表和名称为tb_person的个人数据表,同时预先插入几条数据。
USE mybatis;
# 创建一个名称为tb_idcard的表
CREATE TABLE tb_idcard( id INT PRIMARY KEY AUTO_INCREMENT,CODE VARCHAR(18) );
# 插入2条数据
INSERT INTO tb_idcard(CODE) VALUES('152221198711020624');
# 创建一个名称为tb_person的表,同理
2.4.2 持久化类IDCard类
创建持久化类IdCard,用于封装身份证属性。
public class IdCard {private Integer id; // 主键idprivate String code; // 身份证号码// 省略getter/setter方法@Overridepublic String toString() {return "IdCard [id=" + id + ", code=" + code + "]";}
}
2.4.3 持久化类Person类
创建持久化类Person,用于封装个人属性。
public class Person {private Integer id; // 主键idprivate String name; // 姓名private Integer age; // 年龄private String sex; // 性别private IdCard card; // 人员关联的证件// 省略getter/setter方法,重写的toString()方法
}
2.4.4 编写IdCardMapper.xml文件
创建身份证映射文件IdCardMapper.xml,并在映射文件中编写一对一关联映射查询的配置信息。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.IdCardMapper"><!-- 根据id查询证件信息 --><select id="findCodeById" parameterType="Integer" resultType="IdCard">SELECT * from tb_idcard where id=#{id}</select>
</mapper>
2.4.5 编写PersonMapper.xml文件
创建人员映射文件PersonMapper.xml,并在映射文件中编写一对一关联映射查询的配置信息。
<select id="findPersonById" parameterType="Integer" resultMap="IdCardWithPersonResult">SELECT * from tb_person where id=#{id} </select>
<resultMap type="Person" id="IdCardWithPersonResult"><id property="id" column="id" /><result property="name" column="name" /><result property="age" column="age" /><result property="sex" column="sex" />
<association property="card" column="card_id" javaType="IdCard”select="com.itheima.mapper.IdCardMapper.findCodeById" />
</resultMap>
2.4.6 引入映射文件
在核心配置文件mybatis-config.xml中,引入IdCardMapper.xml和PersonMapper.xml映射文件,并为com.itheima.pojo包下的所有实体类定义别名。
<!-- 只展示了定义别名和mapping文件中配置新添加的部分-- >
<!--使用扫描包的形式定义别名 -->
<typeAliases><package name="com.itheima.pojo" />
</typeAliases>
<mappers><mapper resource="com/itheima/mapper/IdCardMapper.xml" /><mapper resource="com/itheima/mapper/PersonMapper.xml" />
</mappers>
2.4.7 编写测试类
在测试类MyBatisTest中,编写测试方法findPersonByIdTest()。
public void findPersonByIdTest() {// 1、通过工具类获取SqlSession对象SqlSession session = MyBatisUtils.getSession();// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息Person person = session.selectOne("com.itheima.mapper." + "PersonMapper.findPersonById", 1);// 3、输出查询结果信息System.out.println(person);// 4、关闭SqlSessionsession.close();}
2.5 多学一招:MyBatis延迟加载的配置
在使用MyBatis嵌套查询方式进行MyBatis关联映射查询时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在mybatis-config.xml中的元素内进行配置。
<settings><!-- 打开延迟加载的开关 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 将积极加载改为消息加载,即按需加载 --> <setting name="aggressiveLazyLoading" value="false"/>
</settings>
3 一对多查询
3.1 用户与订单关联关系图
3.2 <collection>元素
在MyBatis中,通过<collection>元素来处理一对多关联关系。<collection>元素的属性大部分与<association>元素相同,但其还包含一个特殊属性一ofType。ofType属性与javaType属性对应,它用于指定实体类对象中集合类属性所包含的元素的类型。
3.3 <collection>元素的配置方式
<collection>元素是<resultMap>元素的子元素,元素有嵌套查询和嵌套结果两种配置方式。
3.3.1 a.嵌套查询方式
<collection property="ordersList" column="id" ofType="com.itheima.pojo.Orders"
select=" com.itheima.mapper.OrdersMapper.selectOrders"/>
3.3.2 b.嵌套查询方式
<collection property="ordersList"ofType="com.itheima.pojo.Orders"><id property="id" column="orders_id" /><result property="number" column="number" />
</collection>
3.4 一对多查询案例
3.4.1 创建数据库
在名为mybatis的数据库中,创建两个数据表,分别为tb_user(用户数据表)和tb_orders(订单表),同时在表中预先插入几条测试数据。
USE mybatis;
# 创建一个名称为tb_user的表
CREATE TABLE tb_user (id int(32) PRIMARY KEY AUTO_INCREMENT,username varchar(32),address varchar(256) );
# 插入3条数据,其他语句省略
INSERT INTO tb_user VALUES ('1', '小明', '北京');
# 创建一个名称为tb_orders的表,同理
3.4.2 创建持久化类Orders
在类中定义订单id和订单编号等属性。
public class Orders {private Integer id; //订单idprivate String number; //订单编号// 省略getter/setter方法@Overridepublic String toString() {return "Orders [id=" + id + ", number=" + number + "]";}
}
3.4.3 创建持久化类Users
在类中定义用户编号、用户姓名、 用户地址以及用户关联的订单等属性。
public class Users {private Integer id; // 用户编号private String username; // 用户姓名private String address; // 用户地址private List<Orders> ordersList; // 用户关联的订单// 省略getter/setter方法@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", address="+ address + ", ordersList=" + ordersList + "]"; }
}
3.4.4 创建用户实体映射文件UsersMapper.xml
在文件中编写一对多关联映射查询的配置。
<mapper namespace="com.itheima.mapper.UsersMapper"><resultMap type="Users" id="UserWithOrdersResult"><!-- 只展示了部分标签内容,一对多关联映射 --><collection property="ordersList" ofType="Orders"><id property="id" column="orders_id"/><result property="number" column="number"/></collection></resultMap>
</mapper>
3.4.5 在核心配置文件mybatis-config.xml中
引入UsersMapper.xml,将UsersMapper.xml映射文件加载到程序中。
<mapper resource="com/itheima/mapper/UsersMapper.xml”/>
3.4.6 在测试类MyBatisTest中
编写测试方法findUserTest()。
public void findUserTest() {// 1.通过工具类生成SqlSession对象SqlSession session = MyBatisUtils.getSession();// 2.查询id为1的用户信息Users users = session.selectOne("com.itheima.mapper."+ "UsersMapper.findUserWithOrders", 1);// 3.输出查询结果信息System.out.println(users);// 4.关闭SqlSessionsession.close();
}
4 多对多查询
4.1 订单和商品多对多关系图
在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键关联订单表的id,中间表中的商品id作为外键关联商品表的id。这三个表之间的关系如图。
4.2 多对多查询案例
4.2.1 STEP 01
在名为mybatis的数据库中创建名称为tb_product的商品表和名称为tb_ordersitem
的中间表,同时在表中预先插入几条数据。
CREATE TABLE tb_product (id INT(32) PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(32), price DOUBLE );
# 插入1条数据,其他省略
INSERT INTO tb_product VALUES ('1', 'Java基础入门', '44.5’);
<!-- tb_ordersitem表的创建省略-->
4.2.2 STEP 02
创建持久化类Product,并在类中定义商品id、商品名称、商品单价等属性,以及与订单关联的属性。
public class Product {private Integer id; private String name; private Double price; private List<Orders> orders; //关联订单属性// 省略getter/setter方法@Overridepublic String toString() {return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";}
}
4.2.3 STEP 03
在商品持久化类中,除了需要添加订单的集合属性外,还需要在订单持久化类(Orders.java)中增加商品集合的属性及其对应的getter/setter方法,Orders类中添加的代码如下。
// 关联商品集合属性
private List<Product> productList;
// 省略getter/setter方法,以及重写的toString()方法
4.2.4 STEP 04
创建订单实体映射文件OrdersMapper.xml,用于编写订单信息的查询SQL语句,并在映射文件中编写多对多关联映射查询的配置信息。
<mapper namespace="com.itheima.mapper.OrdersMapper"><select id="findOrdersWithPorduct"parameterType="Integer" resultMap="OrdersWithProductResult">select * from tb_orders WHERE id=#{id} </select><resultMap type="Orders" id="OrdersWithProductResult">
<id property="id" column="id" /><result property="number" column="number" /><collection property="productList" column="id" ofType="Product" select=“com.itheima.mapper.ProductMapper.findProductById" ></collection></resultMap>
</mapper>
4.2.5 STEP 05
创建商品实体映射文件ProductMapper.xml,用于编写订单与商品信息的关联查询SQL语句。
<mapper namespace="com.itheima.mapper.ProductMapper"><select id="findProductById" parameterType="Integer" resultType="Product">SELECT * from tb_product where id IN(SELECT product_id FROM tb_ordersitem WHERE orders_id = #{id} )</select>
</mapper>
4.2.6 STEP 06
将新创建的映射文件OrdersMapper.xml和ProductMapper.xml的文件路径配置到核心配置文件mybatis-config.xml中。
<mapper resource="com/itheima/mapper/OrdersMapper.xml" />
<mapper resource="com/itheima/mapper/ProductMapper.xml" />
4.2.7 STEP 07
在测试类MyBatisTest中,编写多对多关联查询的测试方法findOrdersTest()。
public void findOrdersTest() {// 1.生成SqlSession对象SqlSession session = MyBatisUtils.getSession(); // 2.查询id为1的订单中的商品信息Orders orders = session.selectOne("com.itheima.mapper."+ "OrdersMapper.findOrdersWithPorduct", 1);System.out.println(orders);// 3.输出查询结果信息session.close();// 4.关闭SqlSession
}
5 MyBatis缓存机制
5.1 一级缓存
5.1.1 MyBatis的一级缓存级别
MyBatis的一级缓存是SqlSession级别的缓存。如果同一个SqlSession对象多次执行完全相同的SQL语句时,在第一次执行完成后,MyBatis会将查询结果写入到一级缓存中,此后,如果程序没有执行插入、更新、删除操作,当第二次执行相同的查询语句时,MyBatis会直接读取一级缓存中的数据,而不用再去数据库查询,从而提高了数据库的查询效率。
5.1.2 举例说明MyBatis的一级缓存级别
例如,存在数据表tb_book,从表中多次查询id为1的图书信息,当程序第一次查询id为1的图书信息时,程序会将查询结果写入MyBatis一级缓存,当程序第二次查询id为1的图书信息时,MyBatis直接从一级缓存中读取,不再访问数据库进行查询。当程序对数据库执行了插入、更新、删除操作,MyBatis会清空一级缓存中的内容以防止程序误读。
5.1.3 案例的查询过程
5.1.4 建立数据库
在mybatis数据库中创建名为tb_book的数据表,同时预先插入几条测试数据。
USE mybatis;
# 创建一个名称为tb_book的表,并插入数据,这里只展示一条
CREATE TABLE tb_book( id INT PRIMARY KEY AUTO_INCREMENT,bookName VARCHAR(255),price double,author VARCHAR(40) );
INSERT INTO tb_book(bookName,price,author) VALUES('Java基础入门',45.0,' 传智播客高教产品研发部');
5.1.5 创建持久化类Book
在Book类中定义图书id、图书名称、图书价格、图书作者属性,以及属性对应的getter/setter方法。
public class Book implements Serializable {private Integer id; // 主键private String bookName; // 图书名称private double price; private String author; // 价格、作者// 省略getter/setter方法@Overridepublic String toString() {return "Book{" +"id=" + id + ", bookName='" + bookName +", price=" + price + ", author='" + author+ '}’; }
}
5.1.6 创建图书映射文件BookMapper.xml
在该文件中编写根据图书id查询图书信息的SQL语句。
<mapper namespace="com.itheima.mapper.BookMapper"><!-- 根据id查询图书信息 --><select id="findBookById" parameterType="Integer"resultType="com.itheima.pojo.Book">SELECT * from tb_book where id=#{id} </select><!-- 根据id更新图书信息 --><update id="updateBook"parameterType="com.itheima.pojo.Book">update tb_book set bookName=#{bookName},price=#{price} where id=#{id} </update>
</mapper>
5.1.7 在核心配置文件mybatis-config.xml中的标签下
引入BookMapper.xml映射文件。
<mapper resource="com/itheima/mapper/BookMapper.xml" />
5.1.8 由于需要通过log4j日志组件查看一级缓存的工作状态
因此需要在pom.xml中引入log4j的相关依赖。
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
5.1.9 创建log4j.properties文件
用于配置MyBatis和控制台的。
#全局日志配置
log4j.rootLogger=DEBUG, Console
#控制台输出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
#日志输出级别,只展示了一个
log4j.logger.java.sql.PreparedStatement=DEBUG
5.1.10 在测试类MyBatisTest中
编写测试方法findBookByIdTest1()。
public void findBookByIdTest1() {// 1.通过工具类生成SqlSession对象SqlSession session1 = MyBatisUtils.getSession();// 2.使用session1查询id为1的图书的信息Book book1 = session.selectOne("com.itheima.mapper." + "BookMapper.findBookById", 1);System.out.println(book1.toString()); // 3.输出查询结果信息// 再次使用session1查询id为1的图书的信息,同2、3步// 4.关闭SqlSessionsession1.close();
}
5.2 二级缓存
5.2.1使用二级缓存的好处
相同的Mapper类,相同的SQL语句,如果SqlSession不同,则两个SqlSession查询数据库时,会查询数据库两次,这样也会降低数据库的查询效率。为了解决这个问题,就需要用到MyBatis的二级缓存。MyBatis的二级缓存是Mapper级别的缓存,与一级缓存相比,二级缓存的范围更大,多个SqlSession可以共用二级缓存,并且二级缓存可以自定义缓存资源。
5.2.2 MyBatis二级缓存的执行过程
在MyBatis中,一个Mapper.xml文件通常称为一个Mapper,MyBatis以namespace区分Mapper,如果多个SqlSession对象使用同一个Mapper的相同查询语句去操作数据库,在第一个SqlSession对象执行完后,MyBatis会将查询结果写入二级缓存,此后,如果程序没有执行插入、更新、删除操作,当第二个SqlSession对象执行相同的查询语句时,MyBatis会直接读取二级缓存中的数据。
5.2.3 MyBatis二级缓存的执行过程图解
5.2.4 二级缓存与一级缓存的不同点
与MyBatis的一级缓存不同的是,MyBatis的二级缓存需要手动开启,开启二级缓存通常要完成以下两个步骤。
5.2.4.1 a.开启二级缓存的全局配置
与使用二级缓存前,需要在MyBatis的核心配置mybatis-config.xml文件中通过元素开启二级缓存的全局配置。
<settings><setting name="cacheEnabled" value="true" /></settings>
5.2.4.1 b.开启当前Mapper的namespace下的二级缓存
开启当前Mapper的namespace下的二级缓存,可以通过MyBatis映射文件中的元素来完成。
<!-- 开启当前Mapper的namespace下的二级缓存-->
<cache></cache>
5.2.5 默认状态的二级缓存可实现的功能
(1)映射文件中所有select语句将会被缓存。
(2)映射文件中的所有insert、update和delete语句都会刷新缓存。
(3)缓存会使用LRU算法回收。
(4)没有刷新间隔,缓存不会以任何时间顺序来刷新。
(5)缓存会存储列表集合或对象的1024个引用。
(6)缓存是可读/可写的缓存,这意味着对象检索不是共享的,缓存可以安全的被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
5.2.6 <cache>元素的属性
如果需要调整级缓存的特性,可通过元素的属性来实现。
5.2.7 修改映射文件BookMapper.xml
在映射文件的元素下追加编写元素开启当前Mapper的namespace的二级缓存。
<!— 开启当前BookMapper的namespace下的二级缓存-->
<cache>
</cache>
5.2.8 在测试类MyBatisTest中
编写测试方法findBookByIdTest1()。
public void findBookByIdTest3() {// 1.通过工具类生成两个SqlSession对象,这里只展示了一个SqlSession session1 = MyBatisUtils.getSession();// 2.使用session1查询id为1的图书的信息Book book1 = session1.selectOne("com.itheima.mapper." + "BookMapper.findBookById", 1);System.out.println(book1.toString()); // 3.输出查询结果信息// 4.关闭SqlSession1session1.close();
}
5.2.9 执行MyBatisTest测试类的findBookByIdTest3()方法
5.2.10 对MyBatis二级缓存的应用案例的运行结果分析
控制台输出了执行SQL语句的日志信息以及查询结果。通过分析SQL语句日志信息可以发现,当第一个SqlSession对象session1执行查询时,Cache Hit Ratio(缓存命中率)为0,程序发送了SQL语句;当第二个SqlSession对象session2执行相同的查询时,Cache Hit Ratio为0.5,程序没有发出SQL语句,这就说明,程序直接从二级缓存中获取了数据。
5.2.11 多个SqlSession在同一个Mapper中执行
在实际开发中,经常会遇到多个SqlSession在同一个Mapper中执行操作,例如,SqlSession1执行查询操作,SqlSession2执行插入、更新、删除操作,SqlSession3又执行和SqlSession1相同的查询操作。当SqlSession1执行查询操作时,程序会将查询结果写入MyBatis二级缓存,当SqlSession2对数据库执行了插入、更新、删除操作后,MyBatis会清空二级缓存中的内容,以防止程序误读。当SqlSession3执行和SqlSession1相同的查询操作时,MyBatis会重新访问数据库。
5.2.12 多学一招:Cache Hit Ratio(缓存命中率)
终端用户访问缓存时,如果在缓存中查找到了要被访问的数据,就叫做命中。如果缓存中没有查找到要被访问的数据,就是没有命中。当多次执行查询操作时,缓存命中次数与总的查询次数(缓存命中次数+缓存没有命中次数)的比,就叫作缓存命中率,即缓存命中率=缓存命中次数/总的查询次数。当MyBatis开启二级缓存后,第一次查询数据时,由于数据还没有进入缓存,所以需要在数据库中查询而不是在缓存中查询,此时,缓存命中率为0。第一次查询过后,MyBatis会将查询到的数据写入缓存中,当第二次再查询相同的数据时,MyBatis会直接从缓存中获取这条数据,缓存将命中,此时的缓存命中率为0.5(1/2)。当第三次查询相同的数据,则缓存命中率为0.66666(2/3),以此类推。
6 案例:商品的类别
6.1 商品表(product)商品类别表(category)详情
现有一个商品表product和一个商品类别表category,商品类别表category和商品表product是一对多的关系。
6.2 案例具体要求
根据表1和表2在数据库分别创建一个商品表product和一个商品类别表category,
并通过MyBatis查询商品类别为白色家电的商品的所有信息。
6.3 项目搭建
创建一个名称为mybatis-demo04的项目。
6.4 数据库准备
在名为mybatis的数据库中,创建两个数据表,分别为product和category,同时在表中预先插入几条测试数据。
USE mybatis;
# 创建一个名称为category的表
CREATE TABLE category (id int(32) PRIMARY KEY AUTO_INCREMENT,typename varchar(40));
# 插入2条数据
INSERT INTO category VALUES (1, '黑色家电');
INSERT INTO category VALUES (2, '白色家电');
# 创建一个名称为product的表,同理
6.5 POJO类准备1
创建持久化类Category,并在类中定义商品类别的相关属性和方法。
public class Category {private Integer id; // 主键idprivate String typename; // 类别名称private List<Product> productList; // 商品集合// 省略getter/etter方法@Overridepublic String toString() {return "Category{" +"id=" + id + ", typename='" + typename +", productList=" + productList + '}'; }
}
6.6 POJO类准备2
创建持久化类Product,并在类中定义相关属性和方法。
public class Product {private Integer id; // 主键idprivate String goodsname; // 商品名称private double price; // 价格// 省略getter/setter方法@Overridepublic String toString() {return “Product{” +“id=” + id + “, goodsname=‘” + goodsname +“, price=” + price + ’}‘; }
}
6.7 编写映射文件
创建商品类别实体映射文件CategoryMapper.xml,并在文件中编写一对多关联映射查询的配置。
<!-- 只展示了select标签的内容 -- >
<!-- 一对多:查看某一商品类别及其关联的商品信息注意:当关联查询出的列名相同,则需要使用别名区分 --><select id="findCategoryWithProduct" parameterType="Integer"resultMap="CategoryWithProductResult">SELECT c.*,p.id as category_id,p.goodsname,p.pricefrom category c,product pWHERE c.id=p.category_id and c.id=#{id}</select>
6.8 修改mybatis-config.xml核心配置文件
在核心配置文件mybatis-config.xml中,引入CategoryMapper.xml,将CategoryMapper.xml映射文件加载到程序中。
<mapper resource="com/itheima/mapper/CategoryMapper.xml" ></mapper>
6.9 编写测试方法
在测试类MyBatisTest中,编写测试方法findCategoryTest()。
public void findCategoryTest() {// 1.通过工具类生成SqlSession对象SqlSession session = MyBatisUtils.getSession();// 2.查询id为2的商品类别信息Category category = session.selectOne("com.itheima.mapper."+ "CategoryMapper.findCategoryWithProduct", 2);System.out.println(category); // 3.输出查询结果信息session.close(); // 4.关闭SqlSession
}
6.10 查看运行结果
执行MyBatisTest测试类的findCategoryTest()方法,控制台会输出结果。
第4章 MyBatis的关联映射和缓存机制相关推荐
- 04ssm_Mybaits关联映射和缓存机制
04ssm_Mybaits关联映射和缓存机制 文章目录 04ssm_Mybaits关联映射和缓存机制 一.关联映射概述 1.数据表的三种关联映射关系 2.Java描述数据表的关联映射关系 3.本单元实 ...
- MyBatis的关联映射之 一对一(嵌套查询/嵌套结果)
关联映射概述 在实际的开发中,对数据库的操作常常会涉及多张表,这在面向对象中就涉及了对象与对象之间的关联关系 针对多表之间的操作, MyBatis 提供了关联映射,通过关联映射就可以很好地处理对象与对 ...
- 深入浅出 MyBatis 的一级、二级缓存机制
一.MyBatis 缓存 缓存就是内存中的数据,常常来自对数据库查询结果的保存.使用缓存,我们可以避免频繁与数据库进行交互,从而提高响应速度. MyBatis 也提供了对缓存的支持,分为一级缓存和二级 ...
- 二、mybatis 多级关联映射配置
一.目的 1.上一篇写了mybatis基本的CURD,接着上一篇实现一个 多级关联 获取一篇文章以及该文章的所有评论.评论的所有回复 二.三张表 news(文章表)comment(评论表)reply( ...
- MyBatis之缓存机制
缓存即为存在内存中的临时数据.将用户经常查询的数据存放在缓存(内存)中,用户去查询数据就不用去每次去数据库中查询,而是去缓存中查询,从而提高了查询的效率,解决了高并发系统的性能问题.MyBatis提供 ...
- 三分钟带你了解mybatis关联映射(案例分析一对一,多对多)
------------------------------------------------原创不易,如若喜欢,请点一点赞吧!----------------------------------- ...
- Mybatis注解实现一对多关联映射(@Many)
mybatis注解实现一对多关联映射 @Select("<script> \n" +"\t\tselect a.*,p.punishment_money, p ...
- MyBatis使用resultMap自定义映射规则与关联映射
一.写在前面 在MyBatis 的全局配置文件中我们可以通过在settings标签中设置 <setting name="mapUnderscoreToCamelCase" v ...
- (转)MyBatis框架的学习(五)——一对一关联映射和一对多关联映射
http://blog.csdn.net/yerenyuan_pku/article/details/71894172 在实际开发中我们不可能只是对单表进行操作,必然要操作多表,本文就来讲解多表操作中 ...
最新文章
- 头脑风暴-如何减少软件项目对于人的依赖性。
- Ant Design Vue select下拉列表设置默认值
- sparksql自定义函数
- python counter用法_10个易被忽视但应掌握的Python基本用法
- aws rds监控慢sql_如何将AWS RDS SQL Server与AWS Glue连接
- 移动电话用户突破6亿大关
- 十二、Shell脚本编程函数应用
- 信息学奥赛一本通评测系统P1332
- ajax响应速度慢,jQuery Ajax请求的响应速度变化
- Angular入门到精通系列教程(14)- Angular 编译打包 Docker发布
- 生活片段(1)-短暂的深圳实习时光
- 弱加密算法有哪几种_常见的几种加密方法
- 荣耀20手机不升级鸿蒙经验
- 想学习影视后期,影视后期行业怎么样?影视后期前景如何、薪资怎么样?
- 阿里云盘视频m3u8播放-python+vue3实现
- Python 字符串
- linux修改mac地址
- 一个淘宝店主真实的开店经历
- 告别消费主义的双12,是华为云12.12会员节真正的意义
- 运用计算机通过动力方程,计算机技术在地下水动力学课程素材建设中的应用
热门文章
- CGM第335期:系统发育分析软件PhyloSuite使用讲演(4月2号上午10点)
- 数据结构和算法笔记(1)数论相关
- lq到底是什么意思_马云说的IQ、EQ、​LQ什么意思,懂了这些才是关键
- 详解派生类构造函数与析构函数
- 语料库建立_通过挖掘covid 19科学语料库建立对病毒的理解
- 【论文阅读笔记】ICML2022 时序异质数据 聚类 深度学习
- 【Azure】Devops下载Azure Agent太慢?我们来手动配置
- 【Java】基于Pdfbox解析PDF文档中指定位置的文字和图片
- 安卓车机root改流浪地球_随时代替安卓!华为鸿蒙系统正式发布,你手机里早就有了.......
- XBee zigbee 使用指南--- Zigbee无线数据传输示例