1.Mybatis简介
- 学习视频:https://www.bilibili.com/vide...
- 持久化:就是将程序的数据在持久状态和瞬时状态转化的过程
- 持久层:完成持久化工作的代码块,统称为Dao层
- MyBatis:简化数据库连接和操作数据库的操作的半持久框架,是目前的主流
- 官网:https://mybatis.org/mybatis-3...
2.第一个Mybatis项目
2.1.配置数据库
= 创建数据库,表,表数据
CREATE TABLE `user` (
`id` int(20) NOT NULL AUTO_INCREMENT,#id不为0,自增
`name` varchar(30) DEFAULT NULL,#name默认null
`pwd` varchar(30) DEFAULT NULL,#pwd默认null
PRIMARY KEY (`id`)#主键索引=id
)ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES(1,'狂神','123456');
INSERT INTO `user` VALUES(2,'张三','123456');
INSERT INTO `user` VALUES(3,'李四','123456');
2.2.搭建环境
父工程导包
mysql
mysql-connector-java
5.1.48
org.mybatis
mybatis
3.5.2
junit
junit
4.12
子工程加载资源过滤器
防止后缀为properties和xml配置文件无法加载
src/main/resources
**/*.properties
**/*.xml
true
src/main/java
**/*.properties
**/*.xml
true
配置resources /mybais-config.xml
-
编写工厂工具类
- spring整合mybatis后,这个操作再mybats-config.xml中配置
public class MyBatisUtil {
/**
* 提升sqlSessionFactory作用域,便于全局使用
*/
private static SqlSessionFactory sqlSessionFactory;
static {
try {
/*
使用Mybatis第一步,获取sqlSessionFactory对象
*/
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* sqlSessionFactory对象获取SQLSession实例
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
2.3.Dao层
- Pojo:User
- Dao:接口;实现类变成了XXXMapper.xml文件
public interface UserDao {
List getUserList();
}
2.4 测试
- 资源过滤异常,见上面的子工程配置资源过滤器
- mapper注册失败异常:在mybatis-config.xml配置
public class UserMapperTest {
@Test
public void getUserList() {
//1 获取是sqlSession对象
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//2 获取的是接口的.class,因为多态
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
//3 建议:最后关闭sqlSession
sqlSession.close();
}
}
3. CRUD
3.1 namespace=接口全类名相同
3.2 select
- id:接口中的方法名
- parameterType:返回结果
- resultType:方法参数
3.3 insert/update/delete
- 增删改需要添加事务,返回值只有int,不用添加resultType
INSERT INTO mybatis.user(id,NAME,pwd) VALUES (#{id},#{name},#{pwd});
update mybatis.user set name = #{name},pwd=#{pwd} where id=#{id};
delete from mybatis.user where id=#{id}
3.4 常见错误
- 增删改sql语句写错
# 增加需要values
insert into mybatis.user(id,NAME,pwd) VALUES (#{id},#{name},#{pwd});
# 修改需要set
update mybatis.user set name = #{name},pwd=#{pwd} where id=#{id};
# 删除需要from
delete from mybatis.user where id=#{id}
- 出现bug,是从后往前看查看原因
3.5 万能map
- 如果数据库字段太多,添加修改需要的bean太多,使用map来封装参数,
- 好处一:避免多余代码
- 好处二:跳过特定的Bean属性,可以随意命名key,保证value是字段的属性就行
3.6 模糊查询
4 配置解析
4.1 mybatis_config.xml
- 在resource中创建mybatis_config.xml
4.2 mybatis中的配置属性
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
4.3 enviroments(环境)
- 事务管理器:transcationManager,默认“JDBC”
- 连接数据库:默认pooled
4.4 properties(属性)
- db.properies
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
4.5 settings(设置)
settings配置 | 解释说明 | 默认状态 |
---|---|---|
cacheEnabled(重要) | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | 默认开启 |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | 默认关闭 |
mapUnderscoreToCamelCase(重要) | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | 默认关闭 |
logImpl(最重要) | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J、LOG4J、STDOUT_LOGGING等,默认关闭 |
4.6 typeAliases(类型别名)
- 作用:mapper.xml配置resultType时,简化书写
4.7 plugins(插件)
后期需要加深学习的两大插件,使Mybatis配置更加简单
- Mybatis-Plus
- MyBatis Generator Core
4.8 mappers(映射器)
- 在mybatis-config.xml中配置mapper映射器
- class和package绑定:接口和mapper配置文件必须同名,是否必须在同一个包下有待学习?
4.9 MyBatisUtil(参数作用域)
名称 | 解释说明 |
---|---|
SqlSessionFactoryBuilder | 一旦创建就不再需要它了,作用域是局部变量=静态代码块先加载 |
SqlSessionFactory | 运行期间一直存在,作用域是应用作用域,使用单例模式或者静态单例模式。 |
SqlSession | 连接到数据库的请求,线程不安全,用完后马上关闭;作用域是方法或者请求中,用完就关闭,关闭操作十分重要 |
public class MyBatisUtil {
//0 提升第三步中sqlSessionFactory作用域
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//1 获取mybatis配置文件
String resource = "mybatis-config.xml";
//2 获取配置文件的输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//3 使用SqlSessionFactoryBuilder().build()创建sqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//4 通过getSqlSession获取session
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
}
5 属性名和字段名不一致
5.1 更改User中的pwd->password
- 模拟实现这个过程,数据库中是pwd,更改Pojo中的User属性为pwd,导致不一致
//查询结果:不一致的字段查询结果为null
User{id=1, name='狂神', password='null'}
5.2 解决办法
- 更改pojo成员属性名 = 数据库字段名:使用起来太low,不推荐
- 使用结果集映射=resultMap:哪个字段不一致,就使不一致的成员属性property映射到数据库的column
6 开启日志
6.1 日志工厂
- 在setting中配置:name = logImpl 大小写和空格不能错
-
LOG4J:必须掌握,步骤:setting配置,导包,配置pro,测试时加载
-
setting配置,+导依赖包
log4j log4j 1.2.17 -
log4j.properties:需要时去网上找一份
# log4j日志系统:通用配置 # Define the root logger with appender file # log=D:\logs log4j.rootLogger = DEBUG, FILE, console # 输出到当前目录文件下的log包中 log4j.appender.FILE=org.apache.log4j.FileAppender log4j.appender.FILE.File=./logs/log4j.log # Set the immediate flush to true (default) log4j.appender.FILE.ImmediateFlush=true # Set the threshold to debug mode log4j.appender.FILE.Threshold=debug # Set the threshold to debug mode # 设置日志信息追加 log4j.appender.FILE.Append=true # Set the maximum file size before rollover # 30MB log4j.appender.FILE.MaxFileSize=5KB # Set the backup index log4j.appender.FILE.MaxBackupIndex=2 # Define the layout for file appender log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout.conversionPattern=%m%n # 将日志输出到控制台 log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}]-[%t]-[%F:%L]-[%p]-[%c]-%m%n #log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd}]-[%t]-[%x]-[%-5p]-[%-10c:%m%n] log4j.appender.console.encoding=UTF-8
-
test中:
static Logger logger = Logger.getLogger(UserMapperTest.class);
public class UserMapperTest { //使用log4j static Logger logger = Logger.getLogger(UserMapperTest.class); @Test public void getUserById() { //1 获取是sqlSession对象 SqlSession sqlSession = MyBatisUtil.getSqlSession(); //2 获取方式一:getMapper UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.getUserById(1); System.out.println(user); //3 建议:最后关闭sqlSession sqlSession.close(); } }
-
- STDOUT_LOGGING :掌握,不用导包,mybatis默认配置了,缺点就是只在控制台显示
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- SLF4J
- NO_LOGGING
7 分页
7.1 limit
- 第一个参数:startIndex=开始分页的下标 = (第几页 - 1 )* pageSize
- 第二个参数:pageSize=分页中每页的大小
- 只有一个参数:默认是从第一个元数到该index下标实现分页
select * from user limit startIndex,pageSize;# startIndex=(第几页-1)*pageSize
select * from user limit index;# 默认从第一个元素到第index个用户
7.2 实现分页
- map和RowbBounds两者都可以实现分页:推荐使用map分页,因为默认key=#{key}
public interface UserMapper {
/**
* 根据id获取一个用户
* @param id 指定
* @return User
*/
User getUserById(int id);
/**
* 通过map分页数据,推荐使用
* @param map 常用
* @return ListUser
*/
List getLimitUser(Map map);
/**
* 了解,不推荐使用,通过RowBounds分页数据
* @return ListUser
*/
List getLimitUserByRowBounds();
}
public class UserMapperTest {
@Test
public void getLimitUser() {
UserMapper userMapper = MyBatisUtil.getSqlSession().getMapper(UserMapper.class);
Map map = new HashMap<>();
//mapper.xml会自动寻找map中的key=#{key}
map.put("startIndex",0);
map.put("pageSize",2);
List limitUser = userMapper.getLimitUser(map);
for (User user : limitUser) {
System.out.println(user);
}
}
@Test
public void getLimitUserBrRowBounds() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//老式的查询分页:使用RowBounds
RowBounds rowBounds = new RowBounds(0, 2);
//语法麻烦
List usersList = sqlSession.selectList("com.ssl.dao.UserMapper.getLimitUserByRowBounds",0,rowBounds);
for (User user : usersList) {
System.out.println(user);
}
}
}
7.3 分页插件
- 自学Mybatis PageHelper插件,公司需要就去网站自学
8 注解配置sql语句
8.1 mybaits-config.xml中配置映射器
8.2 缺点
- 如果表中列名和成员属性名不一致,查出来就是null
8.3 注解的CRUD
-
学习@param(非常重要)
- 基本类型、String建议都加上,引用类型不用加
- (uid)中的就是sql中的#{uid}
public interface UserMapper {
/**
* 使用注解开发,有局限性就是column 必须与 dao接口成员属性名一致,否知输出就是null,查不出来
* 所以注解语句开发,便于使用简单场景
*/
@Select("select * from user")
List getUsers();
/**
* @param id=uid
* @return User
*/
@Select("select * from user where id = #{uid}")
User getUserById(@Param("uid") int id);
}
- 增删改自动提交事务
public static SqlSession getSqlSession() {
//不推荐使用,建议手动提交commit
return sqlSessionFactory.openSession(true);
}
9 Lombok
9.1 IDEA中安装Lombok插件
9.2 maven安装依赖
org.projectlombok
lombok
1.18.12
9.3 @Data等注解
- @Data:最常用,自动加上Setter Getter equals tostring,
- @AllArgsConstructor:有参构造
- @NoArgsConstructor:无参构造
9.4 缺点
- 虽然可以混合使用,但多重的构造器的构造器不能重载
- 公司用就用,不用就少用,因为改变了java源码的书写习惯,不利于推广
10 多对一
- 导入Lombok插件和依赖,减少pojo代码
-
新建实体类Student、Teacher和数据库表
- Student中有一个字段tid使用外键约束,关联Teacher
CREATE TABLE `student` (
`id` int(10) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`tid` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `teacher` (
`id` int(10) NOT NULL,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 配置环境:pojo和mapper接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
//需要关联一个老师类
private Teacher teacher;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
}
public interface StudentMapper {
//子查询
List getStudents();
//联表查询
List getStudents1();
}
10.1:子查询=查询嵌套
-
mapper.xml
- 以下对于理解非常重要
- javaType=“teacher”配置了别名,大小写都可以,去pojo路径中中找Teacher,然后使用其成员属性tid
- 测试
@Test
public void getStudents() {
StudentMapper studentMapper = MyBatisUtil.getSqlSession().getMapper(StudentMapper.class);
List students = studentMapper.getStudents();
for (Student student : students) {
System.out.println(student);
}
/*
Student(id=1, name=小红, teacher=Teacher(id=1, name=秦老师))
*/
}
10.2:联表查询=结果嵌套
- 使用多表查询,避免写多个sql
- mapper.xml
- 测试:与嵌套查询结果没变
@Test
public void getStudents1() {
StudentMapper studentMapper = MyBatisUtil.getSqlSession().getMapper(StudentMapper.class);
List students = studentMapper.getStudents1();
for (Student student : students) {
System.out.println(student);
}
/*
Student(id=1, name=小红, teacher=Teacher(id=0, name=秦老师))
*/
}
11 一对多
- 配置环境:pojo和dao下的mapper接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private int tid;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
//一对多的集合
private List students;
}
public interface StudentMapper {
}
public interface TeacherMapper {
/**
* 子查询:按查询嵌套查询
* @param tid
* @return
*/
Teacher getTeacher(@Param("id") int tid);
/**
* 联表查询:按结果嵌套查询
* @param tid
* @return
*/
Teacher getTeacher1(@Param("id") int tid);
}
11.1: 子查询
测试:
@Test
public void getTeacher() {
TeacherMapper teacherMapper = MyBatisUtil.getSqlSession().getMapper(TeacherMapper.class);
Teacher teacher = teacherMapper.getTeacher(1);
System.out.println(teacher);
/*
如果id=0怎么解决?就是collection中配置result property="id" column="id"
Teacher(id=1, name=秦老师, students=[Student(id=1, name=小红, tid=1),Student(id=2, name=小明, tid=1)...
*/
}
11.2: 联表查询
测试:
@Test
public void getTeacher1() {
TeacherMapper teacherMapper = MyBatisUtil.getSqlSession().getMapper(TeacherMapper.class);
Teacher teacher = teacherMapper.getTeacher1(1);
System.out.println(teacher);
/*
Teacher(id=1, name=秦老师, students=[Student(id=1, name=小红, tid=1), Student(id=2, name=小明, tid=1)...
*/
}
11.3: 多表查询小结
- 多对一中的一:association
- 一对多中的多:collection
-
javaType & ofType
- javaType:指定实体类中的属性的java返回值类型
- ofType:映射List或某些指定的pojo泛型的类型,联想List中的泛型类型Student用ofType绑定
-
注意点:
- 保证SQL的可读性,建议使用联表查询
11.4: 面试题自学补充
- MySQL引擎
- InnoDB底层原理
- 索引和索引优化
12 动态SQL
- 概念:动态 SQL 是 MyBatis 的强大特性之一,简化了原生复杂SQL书写
-
四个判断条件:
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
- 搭建数据库
CREATE TABLE blog(
id VARCHAR(50) NOT NULL COMMENT '博客id',
title VARCHAR(100) NOT NULL COMMENT '博客标题',
author VARBINARY(30) NOT NULL COMMENT'博客作者',
# 数据库时间DateTime类型=pojo中的Date类型
# 下划线命名调到pojo中的驼峰式命令,需要mybatis开启驼峰式命令
create_time DATETIME NOT NULL COMMENT'创建时间',
views INT(30) NOT NULL COMMENT'浏览量'
)ENGINE=INNODB DEFAULT CHARSET = utf8;
- pojo和驼峰式命名
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
private String id;
private String title;
private String author;
/**
* 下划线命名调到pojo中的驼峰式命令,需要mybatis开启驼峰式命令
*/
private Date createTime;
private int views;
}
- Utils
public class MyBatisUtil {
/**
* 提升sqlSessionFactory作用域,便于全局使用
*/
private static SqlSessionFactory sqlSessionFactory;
static {
try {
/*
使用Mybatis第一步,获取sqlSessionFactory对象
*/
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* sqlSessionFactory对象获取SQLSession实例
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
}
//随机产生数据库表中的views
public class UUIDUtils {
public static String getId() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
@Test
public void getUUId() {
System.out.println(UUIDUtils.getId());
}
}
- mapper接口
public interface BlogMapper {
int addBlog(Blog blog);
List queryBlogByIf(Map map);
List queryBlogByWhere(Map map);
List queryBlogByForeach(Map map);
}
if
- 概念:sql常见的场景就是判断使用
-
方式一:通过< if >直接使用,或者< include>跳转sql使用时候,需要保证where成立,所以需要在sql语句中加上类似
where 1= 1
或者where state = 'active'
等语句- 这里使用了SQL片段复用,见后面讲解
and title like #{title}
and author like #{author}
- 方式二:通过< where >和< if >混合使用,就不用手动加上
where 1= 1
- 测试:模糊查询需要封装通配符
@Test
public void queryBlogByIf() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map map = new HashMap<>();
//模糊查询,使用map的好处
map.put("title", "%my%");
List blogs = blogMapper.queryBlogByIf(map);
System.out.println(blogs);
sqlSession.close();
}
@Test
public void queryBlogByWhere() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map map = new HashMap<>();
//map.put("id","%4%");
map.put("views", "%2%");
List blogs = blogMapper.queryBlogByWhere(map);
System.out.println(blogs);
sqlSession.close();
}
choose
- 概念:有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
- 需求:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG
- 细节:choose只能满足其中一个whenotherwisw;使用
WHERE state = ‘ACTIVE’
等保证where成立
where
- 单独使用< if > 的缺点:如果没有查询条件或者第一个条件没有满足,就会出现错误的sql语句:
- 出现错误sql:
# 没有条件成立
SELECT * FROM BLOG
WHERE
# 第一个条件没有成立
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
-
使用< where >
- 优势:where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
-
使用自定义 trim 元素来定制 where 元素的功能
-
与< where>等价的< trim>
- prefix="WHERE"满足条件,自动添加的字段:prefixOverrides自动忽略的字段,细节:AND |OR 两者后面都包含了一个空格,这是正确sql的书写要点
-
...
set
-
概念:用于动态update语句的叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列
- 等价的trim语句,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)= 也就是说其实mybatis自动在update中set就给你加上了逗号,但是你自己手写加上了,< set> 也会给你忽略掉
...
update Author
username=#{username},
password=#{password},
email=#{email},
bio=#{bio}
where id=#{id}
foreach
- 概念:动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
- 原生:
SELECT * FROM blog WHERE 1=1 AND (id=1 OR id=2);
- 细节:if < where> 多个条件成立时,就会忽略掉原生中and书写
SQL片段
- 回顾:前面的< where >结合< if>,我们将公共的SQL语句抽取出来,复用.
- 使用:< sql id= > 标签和< include refid= >引用
-
细节:
- 最好基于单表使用sql片段,多表别的表不一定支持
- 使用sql片段复用,不要使用< where >标签,因为它内置了会忽略掉某些字段
and title like #{title}
and author like #{author}
bind(了解)
- bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:
13 缓存
- 我们再次查询相同数据时候,直接走缓存,就不用再存了,解决速度问题
-
什么样的数据需要用到缓存?
- 经常查询并且不经常改变的数据,可以使用缓存
缓存原理图(重要)
二级缓存工作原理:
- 一次sqlsession是一级缓存,查询操作结束后,是默认保存在一级缓存中的
- 如果开启二级缓存,必须先关闭一级缓存,这时候的缓存数据会保存到二级缓存中
- 第二次查询时候,用户操作会嫌去二级缓存中查找
一级缓存
-
默认情况下,只启用了本地的会话(一级)缓存,它仅仅对一个会话中的数据进行缓存。
- 把一级缓存想象成一个会话中的map,便于理解
-
缓存失效
- 增删改会把所有的sql缓存失效,下次会重写从数据库中查
- 查询不同的东西,查询不同的mapper.xml
- 手动清除缓存:
sqlSession.clearCache();
二级缓存
- mybatis-config,xml开启全局缓存
-
mappper.xml开启二级缓存:
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
-
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
- 读写缓存需要pojo开启序列化操作
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private int id;
private String name;
private String pwd;
public static void main(String[] args) {
new ArrayList<>();
new HashMap<>();
new LinkedList<>();
}
}
-
开启二级缓存时,可以指定参数
-
eviction:清楚算法,默认LRU
-
LRU
– 最近最少使用:移除最长时间不被使用的对象。 -
FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。 -
SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。 -
WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
-
- flushInterval:刷新缓存间隔,默认无
- size:最多缓存数量,默认1024
- readOnly:只读缓存;写操作会不走缓存,直接从数据库查询,默认是读/写缓存
-
-
使用二级缓存
- 测试语句
public class MyTest {
@Test
public void queryUserById() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
SqlSession sqlSession1 = MyBatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
//关闭上次sqlSession,如果开启二级缓存,就会把这次的一级缓存保存到二级缓存中
sqlSession.close();
System.out.println("=================");
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
//如果开启二级缓存,下次相同mapper的查询操作会先重二级缓存中查找
User user1 = mapper1.queryUserById(1);
sqlSession1.close();
}
}
自定义缓存(了解)
- 概念:ehcache是一个分布式缓存,主要面向通用缓存
- 手写或者导入第三方的ehcache缓存依赖
- 所以可以自定义ehcache.xml配置文件
org.mybatis.caches
mybatis-ehcache
1.2.0
- 在mapper.xml中配置
- 在resource中创建ehcache.xml文件:
Redis
- 自学,另一个开始