1.2 常用框架 框架是软件的半成品,完成了软件开发过程中的通用操作,程序员只需要很少或不需要进行加工就能实现特定的功能,从而简化开发过程,提高效率。
-
MVC框架:简化了Servlet的开发步骤
- Struts2
- SpringMVC
-
持久层框架:完成数据库操作的框架
- apache DBUtils
- Hibernate
- Spring JPA
- MyBatis
-
平台框架:整合不同功能的框架
- Spring
1.3 MyBatis介绍 SSM - Spring SpringMVC MyBatis
SSH - Spring Struts2 Hibernate
MyBatis是一个半自动的ORM框架:
半自动:因为Hibernate是一个全自动的框架
ORM:Object Relational Mapping,对象关系映射,将Java中的一个对象于数据表中的一行记录一一对应。
ORM框架提供了实体类于数据表的映射关系,通过映射文件的配置,实现对象的持久化。
- MyBatis的前身是iBtis,是由apache基金维护的一个开源项目
- 在2010年时,iBatis迁移到了(代码托管)Google Code,正式更名为MyBatis
- 在2013年时,MyBatis迁移到了github
- MyBatis的特点:
- 支持自定义SQL,支持存储过程
- 对原有的JDBC进行了封装,几乎消除了所有的JDBC代码(打开连接,加载执行SQL…),开发者只需要关注SQL
- 支持XML和注解配置方式自动完成ORM操作,实现结果映射
2.1 创建Maven项目 框架部署,就是将框架引入项目中
- Java工程
- Web工程
- 在pom.xml中添加依赖,以下两个依赖都需要
- Mysql Driver
- MyBatis
2.3 创建MyBatis配置文件mysql mysql-connector-java 5.1.47 org.mybatis mybatis 3.4.6
在maven项目的main文件夹下有一个resources文件夹,在此文件夹下新建一个mybatis的配置文件。可以先添加Mybatis配置文件模板。
三、MyBatis框架使用
3.1 创建数据表 案例:学生信息数据库操作
create table tb_students( sid int primary key auto_increment, stu_num char(5) not null UNIQUE, stu_name VARCHAR(20) not null, stu_gender char(2) not null, stu_age int not null )3.2 创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
private int stuId;
private String stuNum;
private String stuName;
private String stuGender;
private String stuAge;
}
3.3 创建DAO接口,定义方法
public interface StudentDAO {
public int insertStudent(Student s);
public int deleteStudent(String stuNum);
}
3.4 创建接口映射文件
- 在resources目录下新建名为mappers的文件夹
- 在mappers中新建名为StudentMapper.xml的配置文件,需要根据模板
- 在映射文件中对DAO中定义的方法进行实现
3.5 将映射文件添加到主配置文件insert into tb_students(stu_num, stu_name, stu_gender, stu_age) values (#{stuNum}, #{stuName}, #stuGender, #{stuAge}) delete from tb_students where stu_name = #{stuNum}
四、单元测试
public class StudentDAOTest {
@Test
public void insertStudent() {
try {
// 加载mybatis配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 会话(连接)工厂,参数为连接信息
SqlSessionFactory factory = builder.build(is);
SqlSession sqlSession = factory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
System.out.println(studentDAO);
// 插入方法
int i = studentDAO.insertStudent(new Student(1, "10002", "李四", "男", 22));
// 手动提交的事务
sqlSession.commit();
System.out.println("插入操作返回的结果, " + i);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void deleteStudent() {
}
}
五、MyBatis的增删改查
5.1 添加案例:学生信息的增删改查
略,上一节已经演示
5.2 删除 根据学号进行删除操作
-
在StudentDAO中定义删除方法
-
在StudentMapper.xml中对接口方法进行“实现”,使用deldete标签
-
测试类中编写测试代码
@Test public void deleteStudent() { try { InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); SqlSession session = factory.openSession(); StudentDAO studentDAO = session.getMapper(StudentDAO.class); int i = studentDAO.deleteStudent("10002"); session.commit(); System.out.println("删除操作的结果, " + i); } catch (Exception e) { e.printStackTrace(); } }
根据学号(主键)修改其他字段信息
-
添加接口方法
public int updateStudent(Student s);
-
添加mapper映射
update tb_students set stu_name = #{stuName}, stu_gender = #{stuGender}, stu_age = #{stuAge} where stu_num = #{stuNum} -
测试方法
@Test public void testUpdateStudent() { try { InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); SqlSession session = factory.openSession(); StudentDAO studentDAO = session.getMapper(StudentDAO.class); int i = studentDAO.updateStudent(new Student(0, "10001", "赵六", "女", 26)); session.commit(); assertEquals(1, i); } catch (Exception e) { e.printStackTrace(); } }
需要注意查询出来的结果和普通Java类的映射关系,有两种写法。
注意:查询是不需要事务的,写不写无所谓。
-
给查出来的字段起别名,并使用指定类名
-
使用resultMap,推荐使用这种,可复用。
@Test
public void testQueryStudent() {
try {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession session = factory.openSession();
StudentDAO studentDAO = session.getMapper(StudentDAO.class);
Student s = studentDAO.queryStudent("10001");
assertNotNull(s);
System.out.println(s.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
5.6 多参数查询
注意:在MyBatis进行条件查询的时候,
1、操作方法只有一个简单类型或者子字符串类型的参数,在mapper配置的时候可以直接通过#{}任意参数直接获取;
2、如果操作方法,有一个对象类型的参数,在mapper配置的时候可以直接使用#{attrname}获取属性的值(attrname必须是该参数对象的属性);
3、如果操作方法有一个map类型的参数,在Mapper配置中可以直接通过#{key}获取对应key的value;
4、操作方法有多个参数,使用@Param注解指定别名.
注意:如果DAO操作方法没有通过@Param指定参数别名,在SQL语句中可以通过arg0,arg1...或者param1, param2...来获取参数。
public ListlistStudentsByPage(@Param("start") int start, @Param("pageSize") int pageSize);
@Test
public void testListStudentByPage() {
try {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession session = factory.openSession();
StudentDAO studentDAO = session.getMapper(StudentDAO.class);
List s = studentDAO.listStudentsByPage(0, 10);
assertNotNull(s);
s.forEach(item -> System.out.println(item.toString()));
} catch (IOException e) {
e.printStackTrace();
}
}
5.7 查询记录总数
public int countStudents();
通过resultMap指定当前的返回值类型为int,不然会报错
5.8 添加操作,回填自动生成的主键
添加操作时,new了一个Student对象,当插入时,stuId应该是数据库中自增的那个主键,应该回填给这个student对象。
insert into tb_students(stu_num, stu_name, stu_gender, stu_age) values (#{stuNum}, #{stuName}, #{stuGender}, #{stuAge})
- useGeneratedKeys是否需要回填
- keyProperty设置回填属性
public class MyBatisUtil {
private static SqlSessionFactory factory;
private static final ThreadLocal local = new ThreadLocal();
static {
try {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
SqlSession sqlSession = local.get();
if (sqlSession == null) {
sqlSession = factory.openSession();
local.set(sqlSession);
}
return factory.openSession();
}
public static T getMapper(Class c) {
SqlSession sqlSession = getSqlSession();
return sqlSession.getMapper(c);
}
}
七、事务管理
7.1 手动提交事务 SqlSession对象
- getMapper(DAO.class):获取Mapper(DAO接口的实例)
- 事务管理:提供事务管理方法
@Test
public void deleteStudent() {
SqlSession session = MyBatisUtil.getSqlSession();
try {
StudentDAO studentDAO = session.getMapper(StudentDAO.class);
int i = studentDAO.deleteStudent("10002");
session.commit(); // 提交
System.out.println("删除操作的结果, " + i);
} catch (Exception e) {
session.rollback(); // 回滚
e.printStackTrace();
}
}
7.2 自动提交事务
factory.openSession()方法可以传一个Boolean类型的参数,表示是否自动提交事务。默认是false。
但是此时如果在程序中有多个数据库操作,若使用自动提交,则第一个操作完成后就自动提交了。此时建议手动管理。
八、MyBatis主配置文件8.1 properties标签 mybatis-config.xml 是 MyBatis主配置文件
注意:配置文件中的标签必须有序,按照如下顺序:properties, settings, typeAliases, typeHandlers, objectFactory, objectWrapperFactory, plugins, environments, databaseIdProvider, mappers
用于设置键值对,或者加载属性文件。
-
在resources文件夹下创建jdbc.properties文件,键值对配置如下:
mysql_driver = com.mysql.jdbc.Driver mysql_url = jdbc:mysql://localhost:3306/testdb?characterEncoding=utf-8 mysql_username = root mysql_password = 123456
-
主配置文件如下,properties标签引入之后,里面可以根据键值对取出数据
设置mybatis工作时的一些属性
8.3 typeAlias标签
8.4 plugins标签
8.5 environments标签 用于配置mybatis插件,例如分页插件。
配置数据库连接信息
- environment标签,用于配置一个单独的数据库连接信息
- transactionManager的type属性有两个值可选:
- JDBC:用JDBC方式自己在代码中进行事务管理
- MANAGED:事务交给容器管理,连接不自己手动处理
- dataSource标签,配置数据库连接信息,type属性的几个取值:
- POOLED
- UNPOOLED
- JNDI
- transactionManager的type属性有两个值可选:
用于载入项目中的映射配置(映射文件,DAO注解)
九、mapper文件配置 9.1 MyBatis Mapper文件的初始化过程 9.2 Mapper文件规范
-
mapper文件的根标签必须为 mapper,mapper有个属性namespace指定实现哪个接口
-
insert声明添加操作
常用属性:
- id,绑定接口方法名
- parameterType,用于指定接口中对应方法的参数类型(可省略)
- useGeneratedKeys,添加操作是否需要主键回填
- keyProperty,指定回填的主键绑定到对象的哪个属性
- timeout,设置此操作的超时时间,如果不设置就一直等待
主键回填的另外一种方式:使用selectKey标签。
-
delete声明删除
-
update修改
-
select查询操作,属性最多的操作
常用属性:
- resultType,指定当前sql执行返回的类型
- resultMap,指定数据表和实体类之间的对应关系
- useCache,是否开启二级缓存
- id
- timeout
- parameterType
-
resultMap指定字段映射关系
-
cache指定缓存属性配置
缓存的配置详见缓存章节
-
sql和include标签,相当于服用,sql标签定义sql语句片段,include引入这个片段。
sid, stu_name, stu_gender
10.1 添加分页插件依赖 分页插件是一个独立于MyBatis框架之外的第三方插件PageHelper
10.2 配置问价com.github.pagehelper pagehelper 5.2.0
在mybatis的主配置文件中通过plugins标签进行配置
10.3 使用
@Test
public void testPageHelper() {
StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class);
PageHelper.startPage(2, 4);
List students = studentDAO.listByPageHelper();
PageInfo pageInfo = new PageInfo(students);
students.forEach(item -> System.out.println(item.toString()));
System.out.println("--------------------------------------------------");
pageInfo.getList().forEach(item -> System.out.println(item.toString()));
}
十一、关联映射
11.1 实体关系
实体关系——数据实体,实体关系事知数据与数据之间的关系
例如:用户和角色,房屋和漏洞,订单和商品
实体关系分为以下四种:
-
一对一:人和身份证,学生和学号,用户基本信息和用户详情
数据表关系:主键关联(用户表主键和详情主键相同,表示匹配的数据)
-
一对多:班级和学生
-
多对一:学生和班级
数据表关系:在多的那一端添加外键和一的那一端主键关联
-
多对多:用户和角色,学生和社团
数据表关系:建立第三章关系表分别和原两张表的主键进行关联
11.3.1 数据表 实例:用户——详情
-- 用户信息表
create table users(
user_id int primary key auto_increment,
user_name varchar(20) not null unique,
user_pwd varchar(20) not null,
user_realname varchar(20) not null,
user_img varchar(100) not null
);
-- 用户详情表
create table details(
detail_id int primary key auto_increment,
user_addr varchar(50) not null,
user_tel char(11) not null,
user_desc varchar(200),
uid int not null unique,
-- constraint users foreign key(uid) reference users(user_id)
);
11.3.2 创建实体类
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int userId;
private String userName;
private String userPwd;
private String userRealName;
private String userImg;
// 内部对象
private Detail detail;
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Detail {
private int detailId;
private String userAddr;
private String userTel;
private String userDesc;
private int userId;
}
11.3.3 插入
插入时需要保证原子性,插入users表的同时也要插入details表。并且在逻辑上使用外键。需要插入users表的时候使用主键回填。
user_name, user_pwd, user_realname, user_img insert into users( ) values (#{userName}, #{userPwd}, #{userRealName}, #{userImg}) user_addr, user_tel, user_desc, user_id insert into details( ) values (#{userAddr}, #{userTel}, #{userDesc}, #{userId})
@Test
public void testUserInsert() {
User u = new User(0, "nickname", "wadwa", "赵六", "01.jpg", null);
Detail d = new Detail(0, "武汉", "18600011125", "这是一条签名", 0);
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try {
UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
int i = userDAO.insertUser(u);
System.out.println("新用户插入, " + i);
d.setUserId(u.getUserId()); // 设置逻辑外键
DetailDAO detailDAO = sqlSession.getMapper(DetailDAO.class);
int j = detailDAO.insertDetail(d);
System.out.println("详情插入, " + j);
sqlSession.commit(); // 提交事务
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback(); // 回滚事务
}
}
11.3.4 一对一关联查询
难点在于,关联的映射,有两种映射方式
-
表连接查询,将内部类属性直接映射
user_name, user_pwd, user_realname, user_img -
使用子查询
-
在另外一张表中使用查询
user_addr, user_tel, user_desc, user_id -
在主表中使用子查询,借助assosiation标签
-
11.4.1 创建表 案例:班级信息(1) —— 学生信息(n)11.4.1
create table classes( cid int primary key auto_increment, cname varchar(20) not null unique, cdesc varchar(100) ); create table students( sid char(5) primary key, sname varchar(20) not null, sage int not null, scid int not null );11.4.2 实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Clazz {
private int classId;
private String className;
private String classDesc;
private List stus;
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String studentId;
private String stuName;
private int stuAge;
private int stuCid;
}
11.4.3 关联查询
当查询一个班级的时候,要关联查询出来这个班级所有的学生
也有两种实现方式
-
连接查询
-
子查询
同时也要配置子查询中的查询接口和mapper。
11.5.1 实体类 实例:学生(n) —— 班级(1)
当查询一个学生的时候,同时查询出对应的班级对象。
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Clazz {
private int classId;
private String className;
private String classDesc;
// private List stus;
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String stuId;
private String stuName;
private int stuAge;
// private int stuCid;
private Clazz clazz;
}
11.5.2 关联查询
- 连接查询:于一对一关系查询差不多
- 子查询:于一对一关系查询差不多
11.6.1 创建数据表 案例:学生和课程
其中需要创建第三章关系表
-- 学生表如上
-- 课程表
create table courses(
cources_id int primary key auto_increment,
cource_name varchar(20) not null
);
-- 选课信息表/成绩表
create table grades(
sid char(5) not null,
cid int not null,
score int not null
);
11.6.2 关联查询
查询学生时,同时查询学生选择的课程
十二、动态SQL 根绝课程编号查询课程时,同时查询选择这门课的学生
12.1 什么是动态SQL 交友网站,电商平台都有筛选功能
Mybatis提供了动态SQL的配置方式来实现多条件查询
12.2 标签 根据查询条件动态的完成SQL的拼接
-
if:满足条件则拼接,否则不拼接
-
choose、when、otherwise:类似于java中的switch,从多个条件中选择一个使用
-
where标签:用于定义where语句
where标签元素只会在子元素返回任何内容的情况下才插入 “WHERe” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
-
trim:如果where标签定义的字句不满足要求,也可以自定义trim元素来定制where元素的功能。比如和where子句等价的自定义trim元素为:
... prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有prefixOverrides属性中指定的内容,并且插入prefix属性中指定的内容。
-
set标签:用于动态更新语句。set元素可以动态的包含需要的列,忽略其他更新的列:
update Author where id=#{id}username=#{username}, password=#{password}, email=#{email}, bio=#{bio} 等价于:
... -
forEach:集合遍历(在构建IN子句时常用)
-
bind:允许创建一个变量,在表达式中动态绑定
-
script:要在带注解的映射器接口类中使用动态的SQL,可以使用script元素
@Update({""}) void updateAuthorValues(Author author);
- ${key}表示获取参数,先获取参数的值拼接到sql语句中,然后再执行该sql。可能引起SQL注入的问题;
- #{key}表示获取参数,先完成sql语句的编译(预编译),预编译之后再将获取的参数设置到SQL中。即先编译成?占位符。这样可以避免SQL注入的问题。
注意:在使用${key}的时候,默认去参数时会当作是对象来取,传参的时候可以用参数对象或者HashMap,如果是普通的值则必须要声明参数类型,在select标签中要添加parameterType属性,而且在传参的时候必须加上@Param才能获取到,哪怕只有一个参数。
pubilc List<...> ambigousSearch(@Param("keyword") String keyword);
十三、MyBatis日志配置
13.1 添加日志框架依赖 MyBatis作为一个封装好的ORM框架,其运行过程没有办法进行跟踪,为了当开发者了解其执行流程及每个执行步骤完成所有的工作,MyBatis框架本身集成了log4j日志框架,对运行的过程进行记录跟踪。我们只需要对MyBatis进行相关的日志配置,就可以看到MyBatis运行过程中的日志信息。
13.2 添加日志配置文件log4j log4j 1.2.17
-
在resources目录下创建名为log4j.properties的文件,必须在该文件夹下创建该名称的文件,因为MyBatis自动加载。
-
在log4j.properties文件中配置日志输出的方式。
这是MyBatis官方的配置
# 声明日志的输出级别及输出方式 log4j.rootLogger=DEBUG,stdout log4j.logger.org,mybatis.example.BlogMapper=TRACE # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # 定义打印格式 %t是线程名称 %5p是日志级别 log4j.appender.stdout.layout.ConversionPattern=[%t] %5p - %n%m
在使用日志框架进行输出日志信息的时候,会根据输出的日志信息的重要程度分为5个级别。由宽松到严格。
| 日志级别 | 说明 |
|---|---|
| DEBUG | 输出调试信息 |
| INFO | 输出提示性信息 |
| WARN | 输出警告信息 |
| ERROR | 一般性错误信息 |
| FATAL | 致命性错误信息 |
连接池:连接池就是用于存储连接对象的一个容器,而容器就是一个集合,且必须是线程安全的,即两个线程不能拿到同一个连接对象。同时还要具备队列的特性:先进先出原则。
使用连接池的好处:避免频繁创建和关闭数据库连接造成的开销,节省系统资源。
14.1 常见的连接池 MyBatis作为一个ORM框架,在进行数据库操作的时候是需要和数据库进行连接的,MyBatis支持基于数据库的连接池的创建方式。
当我们配置MyBatis数据源的时候,只配置了dataSource标签的type属性值为POOLED时,就可以使用MyBatis内置的连接池管理连接。
如果我们想要使用第三方的数据库连接池就需要自己配置。
-
JDBC
-
DBCP
-
C3P0
-
Druid:性能比较好,提供了比较便捷的监控系统,在企业中使用的比较多,阿里开源
-
HiKari:性能最好
14.3 创建Druid连接池工厂com.alibaba druid 1.2.8
创建一个类继承PooledDataSourceFactory,在无参构造器中设置dataSource为DruidDataSource
public class DruidDataSourceFactory extends PooledDataSourceFactory {
public DruidDataSourceFactory() {
this.dataSource = new DruidDataSource();
}
}
14.4 将Druid连接池工厂配置给MyBatis数据源
在MyBatis主配置文件中,使用DruidDataSourceFactory。
十五、MyBatis缓存 同时,Druid需要的参数是driverClass和jdbcUrl这和POOLED模式不一样。
15.1 缓存的工作原理 MyBatis是基于JDBC的封装,使得数据库操作更加便捷,MyBatis除了对JDBC进行操作步骤进行封装之外也对其性能进行了优化:
- 在MyBatis中引入了缓存机制,用于提升MyBatis的检索效率
- 在MyBatis中引入了延迟加载机制,用于减少对数据库的不必要的访问
- 检查缓存中是否存在要查询的数据;
- 如果存在,则直接从缓存获取数据并返回,减少了访问数据库的次数,大大提升效率;
- 如果不存在则从数据库中查询,查询之后将数据返回,同时存储到缓存中,一共下次查询使用。
15.2.1 一级缓存 MyBatis中的缓存分为一级缓存和二级缓存
一级缓存也叫做SqlSession级缓存,为每个SqlSession单独分配缓存内存,无需手动开启即可直接使用;多个SqlSession的缓存是不共享的。
一级缓存的特性:
- 如果多次查询使用的是同一个SqlSession对象,则第一次查询之后数据会存放到缓存,后续的查询则直接访问缓存;
- 如果第一次查询之后,对查询出来的对象进行修改,此修改会影响到缓存,第二次查询会直接访问缓存,造成查询出来的结果于数据库不一致。
- 当想要跳过缓存直接查询数据库的时候,可以通过sqlSession.clearCache()来清除当前SqlSession对象的缓存。
- 如果第一次查询之后,第二次查询之前使用当前的sqlSession进行更新,则缓存失效,第二次查询直接访问数据库。
存在的问题
- 第一次查询之后,进行了修改操作,数据库已经被修改,但是第二次查询的时候依然显示修改前的数据
- 分析:修改和查询不是同一个线程,因此使用不同的dao对象(使用了不同的SqlSession),因此修改不会导致查询操作的缓存失效;
- 解决思路有两种
- 让查询和修改使用相同的SqlSession对象(不太合理);
- 让每次进行查询操作之后清空缓存。
二级缓存也称为SqlSessionFactory级的缓存。通过同一个factory对象获取的SqlSession可以共享二级缓存;在应用服务器中SqlSessionFactory是 单例的,因此二级缓存的数据可以全局共享。
二级缓存特性:
-
二级缓存默认没有开启,需要在mybatis-config.xml中的setting标签中进行开启,
另外在mapper文件内只要使用了chche标签则,则开启了二级缓存。这个标签有一些参数,eviction设置缓存回收策略,取值LRU(默认),FIFO,SOFT,WEAK。flushInterval设置刷新间隔,默认是不清空。readOnly是否只读。size指定大小。type指定自定义缓存的全类名,实现Cache接口即可。
-
二级缓存只能缓存实现了序列化接口的对象;
-
先判断二级缓存是否开启,如果没开启,再判断一级缓存是否开启,如果没开启,直接查数据库
-
如果一级缓存关闭,即使二级缓存开启也没有数据,因为二级缓存的数据从一级缓存获取
-
一般不会关闭一级缓存
-
二级缓存默认不开启
-
如果二级缓存关闭,直接判断一级缓存是否有数据,如果没有就查数据库
-
如果二级缓存开启,先判断二级缓存有没有数据,如果有就直接返回;如果没有,就查询一级缓存,如果有就返回,没有就查询数据库;
十六、延迟加载 综上所述:先查二级缓存,再查一级缓存,再查数据库;即使在一个sqlSession中,也会先查二级缓存;一个namespace中的查询更是如此;
延迟加载是指,如果在MyBatis执行了子查询(至少查询两次以上),默认只执行第一次查询,当用到子查询的查询结果时,才会触发子查询的执行。如果没有使用子查询的结果,则子查询不会进行。
需要配置MyBatis的主配置文件



