21.sql片段
<!--sql片段-->
<sql id="columnBase">
`id`,
`name`,
`age`,
`title`,
`author_id`,
`featured`,
`state`,
`style`
</sql>
<!--通过id查询博客-->
<select id="selectBlog" parameterType="Integer" resultType="Blog">
select
<include refid="columnBase"/>
from blog where id = #{id}
</select>
22 23.逆向功工程-代码的生成
使用 Mybatis 官方工具直接生成对应的mapper文件
全部生成 - 无实际意义,具体项目中不适用
24.缓存 - mybatis的一级缓存
一级缓存:
是session级别的缓存,一级缓存默认存在。
当在同一个session范围内执行查询的时候,如果执行相同的查询,那么第二次查询会从缓存中获取数据。
/**
* mybatis的一级缓存
*/
@Test
public void testSelectBlogCacheOne1() {
SqlSession session = MyBatisUtil.getSqlSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
Blog blog1 = blogMapper.selectBlog(3);
System.out.println("结果已查询" + blog1);
Blog blog2 = blogMapper.selectBlog(3);
System.out.println("结果已查询:从缓存中获取数据" + blog2);
session.close();
System.out.println("session关闭");
}
25.缓存 - 一级缓存被刷新的情况
如果两次查询中间有增删改操作,sql session缓存区会被自动清空,说明下一次查询会重新执行sql语句。
/**
* mybatis的一级缓存,中间有增删改会刷新
*/
@Test
public void testSelectBlogCacheOne2() {
SqlSession session = MyBatisUtil.getSqlSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
Blog blog1 = blogMapper.selectBlog(3);
System.out.println("结果已查询" + blog1);
blog1.setFeatured(true);
blogMapper.updateBlog(blog1);
Blog blog2 = blogMapper.selectBlog(3);
System.out.println("结果已查询:从新执行查询" + blog2);
session.commit();
session.close();
System.out.println("session关闭");
}
26.缓存 - 开启二级缓存
默认不开启。如果在不同的session范围内执行相同的数据查询,那么每次查询将会执行独立的数据库检索过程。
/**
* mybatis的二级缓存
*/
@Test
public void testSelectBlogCacheLevelTwo1() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
Blog blog1 = blogMapper1.selectBlog(3);
System.out.println("结果已查询" + blog1);
session1.close();
SqlSession session2 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper2 = session2.getMapper(BlogMapper.class);
Blog blog2 = blogMapper2.selectBlog(3);
System.out.println("结果已查询:从缓存中获取数据" + blog2);
session2.close();
System.out.println("session关闭");
}
开启二级缓存
1.在mapper文件中设置 <cache/>
2.在实体类中实现序列化接口
public class Blog implements Serializable {
private static final long serialVersionUID = 1L;
}
/**
* mybatis的二级缓存
*/
@Test
public void testSelectBlogCacheLevelTwo1() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
Blog blog1 = blogMapper1.selectBlog(3);
System.out.println("结果已查询" + blog1);
session1.close();
// Cache Hit Ratio [mapper.BlogMapper]: 0.5
SqlSession session2 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper2 = session2.getMapper(BlogMapper.class);
Blog blog2 = blogMapper2.selectBlog(3);
System.out.println("结果已查询:从缓存中获取数据" + blog2);
session2.close();
System.out.println("session关闭");
}
27.缓存 - 二级缓存被刷新的情况
和一级缓存相同,中间有增删改则二级缓存会被清空
/**
* mybatis的二级缓存 缓存被刷新
*/
@Test
public void testSelectBlogCacheLevelTwo2() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
Blog blog1 = blogMapper1.selectBlog(3);
blog1.setFeatured(true);
blogMapper1.updateBlog(blog1);
System.out.println("结果已查询" + blog1);
session1.close();
SqlSession session2 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper2 = session2.getMapper(BlogMapper.class);
Blog blog2 = blogMapper2.selectBlog(3);
System.out.println("缓存被刷新,重新查询" + blog2);
session2.close();
System.out.println("session关闭");
}
28.嵌套查询 - 一对一和多对一
高级结果映射
一、关联映射(适用于一对一和多对一的情况)
1).创建pojo
(1)在Blog中创建Author对象
private Author author;
(2)创建Author的pojo
2).配置mapper
BlogMapper.java
<resultMap type="Blog" id="blogResultMap">
<id column="id" property="id" jdbcType="INTEGER"></id>
<association property="author" column="author_id" javaType="Author"
select="me.jing.mapper.AuthorMapper.selectAuthorById">
</association>
</resultMap>
<select id="selectBlogById" parameterType="int" resultMap="blogResultMap">
select * from blog where id = #{id}
</select>
AuthorMapper.java
<resultMap type="Author" id="authorResultMap">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="favourite_section" property="favouriteSection" jdbcType="VARCHAR"/>
</resultMap>
<select id="selectAuthorById" parameterType="int" resultMap="authorResultMap">
select * from author where id = #{id}
</select>
- 接口
(1) Blog
Blog selectBlogById(Integer id);
(2) Author
Author selectAuthorById(Integer id);
- 测试
查询Blog列表时,执行的sql语句是 1+n,但是如果blog关联的author有重复的数据,那么从一级缓存中查询。
/**
* 通过id查具体的博客,查询时 再拿到作者id 去作者表查具体的作者信息
*/
@Test
public void testSelectBlogById() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
Blog blog = blogMapper1.selectBlogById(3);
session1.close();
System.out.println("结果已查询" + blog);
}
29.嵌套查询 - 显示信息列表
<select id="selectBlogList" resultMap="blogResultMap">
select * from blog
</select>
List<Blog> selectBlogList();
@Test
public void testSelectBlogList() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
List<Blog> blogs = blogMapper1.selectBlogList();
session1.close();
System.out.println("结果已查询" + blogs);
}
30.嵌套查询-一对多的配置 31.嵌套查询-一对多的查询配置
执行流程:1.先执行单表查询,2.再利用单表查询的结果继续执行其他单表查询,3.最后组装结果映射。
通过post的id 查询post表的内容,同时通过此id查询评论表 comment 里的数据列表,即这篇文章的评论列表
sql:
create table post(id int,blog_id int,author_id int,
section varchar(20),subject varchar(20),draft varchar(20));
insert into post(id,blog_id,author_id,section,subject,draft)
values('1','3','15','section','subject','draft');
create table comment(id int,
name varchar(20),comment varchar(20));
insert into comment(id,name,comment,post_id)
values('1','评论name','我觉得很棒 评论','1');
PostMapper.xml
<resultMap type="Post" id="postResultMap">
<id column="id" property="id" jdbcType="INTEGER"></id>
<collection property="commentList" column="id" javaType="ArrayList" ofType="Comment"
select="me.jing.mapper.CommentMapper.selectCommentListByPostId"></collection>
</resultMap>
<select id="selectPostById" parameterType="int" resultMap="postResultMap">
select * from post where id = #{id}
</select>
CommentMapper.xml
<resultMap type="Comment" id="commentResultMap">
<id column="id" property="id" jdbcType="INTEGER"></id>
</resultMap>
<!--通过post_id查询评论列表-->
<select id="selectCommentListByPostId" parameterType="int" resultMap="commentResultMap">
select * from comment where post_id = #{postId}
</select>
<select id="selectCommentById" parameterType="int" resultMap="commentResultMap">
select * from comment where id = #{id}
</select>
测试:
/**
* 通过post的id 查询post表的内容,
* 同时通过此id查询评论表 comment 里的数据列表,即这篇文章的评论列表
*/
@Test
public void selectPostById() {
SqlSession session1 = MyBatisUtil.getSqlSession();
PostMapper mapper = session1.getMapper(PostMapper.class);
Post post = mapper.selectPostById(1);
System.out.println("结果已查询" + post);
session1.close();
}
32.高级结果映射-嵌套结果
1).先执行关联查询,一次性将所有数据都查询出来
2).再将所有查询出来的列组织成嵌套的结果对象
SELECT * FROM
blog b
LEFT JOIN author a
ON b.author_id = a.id;
SELECT
b.id as blog_id,
b.title as blog_title,
b.author_id as blog_author_id,
b.state as blog_state,
b.featured as blog_featured,
b.style as blog_style,
a.id as author_id,
a.username as author_username,
a.password as author_password,
a.email as author_email
FROM blog b
LEFT JOIN author a
ON b.author_id = a.id;
BlogMapper.xml
<resultMap id="blogResultMapNested" type="Blog">
<id column="blog_id" property="id"/>
<result column="blog_title" property="title"/>
<result column="blog_state" property="state"/>
<result column="blog_featured" property="featured"/>
<result column="blog_style" property="style"/>
<!--<result column="blog_author_id" property="author_id"/>-->
<association property="author" column="blog_author_id" javaType="Author">
<id column="author_id" property="id"/>
<result column="author_username" property="username"/>
<result column="author_password" property="password"/>
<result column="author_email" property="email"/>
</association>
</resultMap>
<!--32.高级结果映射-嵌套结果-->
<select id="selectBlogListNested" resultMap="blogResultMapNested">
SELECT
b.id as blog_id,
b.title as blog_title,
b.author_id as blog_author_id,
b.state as blog_state,
b.featured as blog_featured,
b.style as blog_style,
a.id as author_id,
a.username as author_username,
a.password as author_password
FROM blog b
LEFT JOIN author a
ON b.author_id = a.id;
</select>
/**
* 嵌套查询
*/
List<Blog> selectBlogListNested();
/**
* 嵌套查询
*/
@Test
public void testSelectBlogListNested() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
List<Blog> blogs = blogMapper1.selectBlogListNested();
session1.close();
System.out.println("结果已查询2:" + blogs);
}
33.为什么要做扩展结果集|34.扩展结果的实现
1).mapper
BlogCustomMapper.xml
<sql id="baseColumn">
b.id,
b.`title`,
b.`author_id`,
b.`state`,
b.`featured`,
b.`style`,
a.username as authorUsername
</sql>
<select id="selectBlogById" parameterType="int" resultType="BlogCustom">
select
<include refid="baseColumn"/>
from blog b
left join author a
on b.author_id = a.id
where b.id = #{id}
</select>
BlogCustomMapper.java
public interface BlogCustomMapper {
BlogCustom selectBlogById(Integer id);
}
2)vo.BlogCustom.java
/**
* 扩展Blog
*/
public class BlogCustom extends Blog {
private static final long serialVersionUID = 1L;
private String authorUsername;
public String getAuthorUsername() {
return authorUsername;
}
public void setAuthorUsername(String authorUsername) {
this.authorUsername = authorUsername;
}
@Override
public String toString() {
return "BlogCustom{" +
"authorUsername='" + authorUsername + '\'' +
'}';
}
}
<!--定义别名-->
<typeAliases>
<!--<typeAlias type="pojo.Blog" alias="Blog"/>-->
<package name="me.jing.pojo"/>
<package name="me.jing.pojo.vo"/>
</typeAliases>
3)测试
/**
* 通过id查具体的博客,查询时 再拿到作者id 去作者表查具体的作者 username
*/
@Test
public void testSelectBlogById() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogCustomMapper mapper = session1.getMapper(BlogCustomMapper.class);
BlogCustom blog = mapper.selectBlogById(3);
session1.close();
System.out.println("结果已查询" + blog);
}
35.高级结果映射 - 构造方式映射
Bolg.xml
public Blog(Integer id, String title) {
this.id = id;
this.title = title;
System.out.println("构造函数调用-----");
}
<!--构造方法映射-->
<resultMap id="blogResultMapConstructor" type="Blog">
<constructor>
<idArg column="id" javaType="int"/>
<arg column="title" javaType="string"/>
</constructor>
</resultMap>
<select id="selectBlogByIdConstructor" parameterType="int" resultMap="blogResultMapConstructor">
select * from blog where id = #{id}
</select>
/**
* 构造方式映射
*/
Blog selectBlogByIdConstructor(Integer id);
/**
* 构造方式映射
*/
@Test
public void testSelectBlogByIdConstructor() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
Blog blog = blogMapper1.selectBlogByIdConstructor(3);
session1.close();
System.out.println("结果已查询:" + blog);
}
36.鉴别器
CREATE TABLE `vehicle`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`vin` VARCHAR(50) COLLATE utf8_bin DEFAULT NULL,
`year` YEAR(4) DEFAULT NULL,
`make` VARCHAR(50) COLLATE utf8_bin DEFAULT NULL,
`model` VARCHAR(50) COLLATE utf8_bin DEFAULT NULL,
`color` VARCHAR(50) COLLATE utf8_bin DEFAULT NULL,
`vehicle_type` INT(11) DEFAULT NULL,
`door_count` INT(11) DEFAULT NULL,
`all_wheel_drive` TINYINT(1) DEFAULT NULL,
PRIMARY KEY(`id`)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
VehicleMapper.xml
<resultMap type="Vehicle" id="vehicleResultMap">
<id column="id" property="id" jdbcType="INTEGER"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultType="Car">
<result column="door_count" property="doorCount"/>
</case>
<case value="2" resultType="Suv">
<result column="all_wheel_drive" property="allWheelDrive"/>
</case>
</discriminator>
</resultMap>
<select id="selectVehicleById" parameterType="int" resultMap="vehicleResultMap">
select * from vehicle where id = #{id}
</select>
Vehicle selectVehicleById(Integer id);
pojo
public class Vehicle {
private Integer id;
private Integer vehicle_type;
private String vin;
private String make;
private String model;
private String color;
private Boolean all_wheel_drive;
}
public class Suv extends Vehicle {
// 全轮驱动 awd
private Boolean allWheelDrive;
public Suv() {
}
public Boolean getAllWheelDrive() {
return allWheelDrive;
}
public void setAllWheelDrive(Boolean allWheelDrive) {
this.allWheelDrive = allWheelDrive;
}
@Override
public String toString() {
return "Suv{" +
"allWheelDrive=" + allWheelDrive +
'}';
}
}
public class Car extends Vehicle {
// 门的数量
private Integer doorCount;
public Integer getDoorCount() {
return doorCount;
}
public void setDoorCount(Integer doorCount) {
this.doorCount = doorCount;
}
@Override
public String toString() {
return "Car{" +
"doorCount=" + doorCount +
'}';
}
}
测试:
/**
* 鉴别器
*/
@Test
public void testSelectVehicleById() {
SqlSession session1 = MyBatisUtil.getSqlSession();
VehicleMapper mapper = session1.getMapper(VehicleMapper.class);
Vehicle vehicle = mapper.selectVehicleById(1);
Vehicle vehicle2 = mapper.selectVehicleById(2);
if (vehicle instanceof Car) {
Car car = (Car) vehicle;
Suv suv = (Suv) vehicle2;
System.out.println("car:" + car);
System.out.println("suv:" + suv);
} else {
Car car = (Car) vehicle2;
Suv suv = (Suv) vehicle;
System.out.println("car:" + car);
System.out.println("suv:" + suv);
}
System.out.println("vehicle:" + vehicle);
System.out.println("vehicle2:" + vehicle2);
session1.close();
}
37.延迟加载 - 不配置延迟加载的情况
测试一:
没有配置任何选项,执行两遍查询,性能比较低
无论是否查询blog的任意属性,都会执行author的任何查询,就是说 始终会执行两次查询。
查询blog----
Opening JDBC Connection
Created connection 504858437.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1e178745]
==> Preparing: select * from blog where id = ?
==> Parameters: 3(Integer)
====> Preparing: select * from author where id = ?
====> Parameters: 15(Integer)
<==== Total: 1
<== Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1e178745]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1e178745]
Returned connection 504858437 to pool.
查询blog的title属性----
Android开发艺术探索
查询blog的author属性----
景彬
结果已查询
38.延迟加载 - 配置lazyloadingenabled
测试二:
如果不查询blog的任意属性,那么不会执行author的查询
配置了全局属性:
<settings>
<!--<setting name="useGeneratedKeys" value="true"/>-->
<!--延迟加载 配置lazyloadingenabled-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
测试:
/**
* 测试延迟加载
* 没有配置 lazyLoadingEnabled 时,会始终执行两次查询
*/
@Test
public void testSelectBlogByIdLazyLoading() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
System.out.println("查询blog----");
Blog blog = blogMapper1.selectBlogById(3);
session1.close();
// System.out.println("查询blog的title属性----");
// System.out.println(blog.getTitle());
// System.out.println("查询blog的author属性----");
// System.out.println(blog.getAuthor().getUsername());
System.out.println("结果已查询");
}
日志打印:
查询blog----
Opening JDBC Connection
Created connection 210156003.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
==> Preparing: select * from blog where id = ?
==> Parameters: 3(Integer)
<== Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Returned connection 210156003 to pool.
结果已查询
39.延迟加载 - 测试用例1和2的比较
40.延迟加载 - 积极的延迟加载
延迟加载:用属性就加载,不用就不加载。
积极的延迟加载:只要用属性,就把所有要查询的属性sql全部执行一遍。
测试三:
只要查询bolg的任意属性,都会执行author数据的查询
配置了全局属性(同测试2的配置):
<settings>
<!--<setting name="useGeneratedKeys" value="true"/>-->
<!--延迟加载 配置lazyloadingenabled-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
测试:
/**
* 测试延迟加载
* 没有配置 lazyLoadingEnabled 时,会始终执行两次查询
*/
@Test
public void testSelectBlogByIdLazyLoading() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
System.out.println("查询blog----");
Blog blog = blogMapper1.selectBlogById(3);
session1.close();
System.out.println("查询blog的title属性----");
System.out.println(blog.getTitle());
// System.out.println("查询blog的author属性----");
// System.out.println(blog.getAuthor().getUsername());
System.out.println("结果已查询");
}
41.延迟加载 - 非积极延迟加载
测试四:
延迟加载,并且是非积极的。如果需要访问blog的非author属性,则不执行关联的author查询。
配置了全局属性:
配置后,没有调用 blog.getAuthor() 属性,就只会执行一次,调用 blog.getAuthor() 属性才回再执行查询author表一次。
<!--具体的insert也得配置 keyProperty-->
<settings>
<setting name="useGeneratedKeys" value="true"/>
<!--延迟加载 配置lazyloadingenabled-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--非积极的延迟加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
测试:
/**
* 测试延迟加载
*/
@Test
public void testSelectBlogByIdLazyLoading() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
System.out.println("查询blog----");
Blog blog = blogMapper1.selectBlogById(3);
session1.close();
System.out.println("查询blog的title属性----");
System.out.println(blog.getTitle());
// System.out.println("查询blog的author属性----");
// System.out.println(blog.getAuthor().getUsername());
System.out.println("结果已查询");
}
打印:
查询blog----
Opening JDBC Connection
Created connection 210156003.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
==> Preparing: select * from blog where id = ?
==> Parameters: 3(Integer)
<== Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Returned connection 210156003 to pool.
查询blog的title属性----
Android开发艺术探索
结果已查询
测试五:
配置了全局属性 同配置四
延迟加载,并且是不积极的。如果访问了blog的author属性,则执行关联的author查询
测试:
/**
* 测试延迟加载
*/
@Test
public void testSelectBlogByIdLazyLoading() {
SqlSession session1 = MyBatisUtil.getSqlSession();
BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
System.out.println("查询blog----");
Blog blog = blogMapper1.selectBlogById(3);
session1.close();
System.out.println("查询blog的title属性----");
System.out.println(blog.getTitle());
System.out.println("查询blog的author属性----");
System.out.println(blog.getAuthor().getUsername());
System.out.println("结果已查询");
}
打印:
查询blog----
Opening JDBC Connection
Created connection 210156003.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
==> Preparing: select * from blog where id = ?
==> Parameters: 3(Integer)
<== Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Returned connection 210156003 to pool.
查询blog的title属性----
Android开发艺术探索
查询blog的author属性----
Opening JDBC Connection
Checked out connection 210156003 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
==> Preparing: select * from author where id = ?
==> Parameters: 15(Integer)
<== Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@c86b9e3]
Returned connection 210156003 to pool.
景彬
结果已查询
网友评论