2.第一个Mybatis程序
思路 : 搭建环境–》导入Mybatis–》编写代码–》测试
2.1搭建数据库
2.2 新建一个maven项目
2.3 导入核心配置文件
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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
2.4 使用mybatis
创建一个com.guo.dao文件 封装好pojo和utils
- 封装工具类
package com.guo.dao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 利用SqlSessionFactory获取SqlSession实例
// SqlSession完全包含了面向数据库执行sql命令所需要的方法
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
-
实体类
package com.guo.pojo; public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
-
写接口(dao/mapper)
userdao
package com.guo.dao; import com.guo.pojo.User; import java.util.List; public interface UserDao { List<User> getUserList(); }
UserMappert.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"> <!--映射语句 namespace=绑定一个对应的DAO/Mapper--> <mapper namespace="com.guo.dao.UserDao"> <!-- sql查询语句 --> <select id="getUserList" resultType="com.guo.pojo.User"> select * from User </select> </mapper>
-
报错
- 问题出在java和resource的xml文件无法被导出
Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/guo/dao/UseMapper.xml
解决办法
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
-
maven无法clean
解决办法: 进入idea --》 file–》settings-》maven 重新配置maven
如果没有下载maven请重新配置环境变量
-
报错字符集编码问题
在父maven项目中的pom.xml文件中
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
3、CRUD
3.1 namespace
namespace中的包名要和Dao/Mapper接口包名一直
3.2 select insert update delete
选择查询
- id: 就是队名namespace的方法名
- resultType: Sql语句执行的返回值
- paramType: 传入参数类型
- 编写接口
- 编写对应的mapper中的sql语句
- 测试
注意:
- 除了select其他的操作需要提交事务
3 万能的map
我们的实体类或者数据库中的表、字段和参数过多,我们应该考虑使用map
Map传递参数,直接在sql中取出key即可
<insert id="insertUser2" parameterType="map">
insert into mybatis.user (id, name, pwd) values(#{userId}, #{userName}, #{password})
</insert>
对象传递参数,直接在sql中取出属性
<insert id="insertUser" parameterType="com.guo.pojo.User">
insert into mybatis.user values(#{id}, #{name}, #{pwd})
</insert>
只有一个基本类型参数的情况下,可以直接在sql中取到 parameterType=“int”(可以省略不写)
4. 模糊查询
-
Java代码在执行的时候传递通配符 %
<!-- sql查询语句 模糊查询 --> <select id="getLikeUser" resultType="com.guo.pojo.User"> select * from mybatis.user where name like #{value}; </select>
List<User> list = userMapper.getLikeUser("%g%");
-
在sql中拼接中使用通配符 “%”
List<User> list = userMapper.getLikeUser("g");
<!-- sql查询语句 模糊查询 --> <select id="getLikeUser" resultType="com.guo.pojo.User"> select * from mybatis.user where name like "%"#{value}"%"; </select>
相比之下,第二种方法更加安全
5.配置解析
5.1 核心配置
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
5.2 环境配置(environments)
mybatis可以配置成适应于多种环境
不过记住:尽管可以配置多种环境,但是每个sqlSessionFactory只能选择一种环境,选择的环境由default字段决定,
学会配置多种环境
<environments default="development">
mybatis中默认的事务管理器 是 JDBC ,连接池:POOLED
5.3 属性(Properties)
我们可以通过properties属性来实现引用配置文件
<properties resource="db.properties" />
db.properties文件
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useUnicode=true;characterEncoding=utf-8;serverTimezone=GMT;nullCatalogMeansCurrent = true
usernname = root
password = 123456
引入文件后,xml中文件可以直接引用properties中的变量
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${root}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
注意:
- properties还有第二种用法==
<properties resource="db.properties" >
<property name="password" value="111111"/>
</properties>
当properties标签中定义键值对和引用文件中的键值对发生冲突时, 外部文件优先级高于内部文件
- 在xml文件中 每一个标签有一个固定的顺序,不能随意更改
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
5.4 类型别名
- 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
两种方式配置别名
-
typeAlias 配置Java Bean文件
<typeAliases> <typeAlias type="com.guo.pojo.User" alias="User"/> </typeAliases>
-
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
<typeAliases>
<package name="com.guo.pojo"/>
</typeAliases>
注意: 第一种方法和第二种方法都能配置别名,
-
但是第一种方法可以自己设置alias,
-
第二种方法在Java Bean没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。;若有注解,则别名为其注解值
@Alias("hello")
public class User {
...
}
5.6.设置settings
需要记住的几个设置
-
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType
属性来覆盖该项的开关状态。true | false false localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 SESSION | STATEMENT SESSION
当遇到设置问题,请去官方文档上查找
5.7. 其他配置
-
typeHandlers(类型处理器)
-
plugin插件
- mybatis-generator-core
- mybatis-plus
- 通用mapper
5.8. 映射器(Mappers)
MapperRegistery: 注册绑定我们的mapper文件
方式一 : 直接使用xml文件名进行绑定
<mappers>
<mapper resource="com/guo/dao/UserMapper.xml"/>
</mappers>
方式二: 使用接口名进行绑定
<mappers>
<mapper class="com.guo.dao.UserMapper" />
</mappers>
注意:
- 使用接口名直接绑定时, 接口文件名和MapperXML文件必须相同
- 两个文件必须在同一个文件夹下
方式三:使用包名扫描绑定
<mappers>
<package name="com.guo.dao"/>
</mappers>
注意:
- 使用接口名直接绑定时, 接口文件名和MapperXML文件必须相同
- 两个文件必须在同一个文件夹下
5.9. 生命周期和作用域
生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qjb5BL21-1621000778478)(C:\Users\MSI\AppData\Roaming\Typora\typora-user-images\image-20210412143621378.png)]
SqlSessionFactoryBuilder
- 一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder了,其最大的作用就是创建SqlSessionFactory
- 因此其最佳作用域为 方法作用域(作用在一个方法内)
SqlSessionFactory
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 最佳作用域是 应用作用域
- 使用单例模式或者静态单例模式。
SqlSession
- 每个线程都应该有它自己的 SqlSession 实例。
- SqlSession 的实例不是线程安全的,因此是不能被共享的,
- 最佳的作用域是 请求或方法作用域。
- 使用后应该立马关闭
5.10.解决属性名和字段名不一致问题
1.问题
当JavaBean和pojo中的对应属性名不同的时候,会发生冲突
例如
User.class
public class User {
private int id;
private String name;
private String password;
}
UserMapper.xml
<select id="getUserList" resultType="user">
select * from mybatis.user;
</select>
查询出来的结果
User{id=1, name='狂神说', password='null'}
User{id=2, name='guo', password='null'}
User{id=10, name='10', password='null'}
User{id=12, name='ghl', password='null'}
解决办法:
-
起别名:
<select id="getUserList" resultType="user"> select id,name,pwd as password from mybatis.user; </select>
2.resultMap 结果集映射
-
resultMap
元素是 MyBatis 中最重要最强大的元素。 -
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
-
ResultMap
的优秀之处——你完全可以不用显式地配置它们。(处理发生冲突字段就行) -
如果这个世界总是这么简单就好了。
例如上述例子
<resultMap id="userResultMap" type="user">
<result property="password" column="pwd"/>
</resultMap>
<select id="getUserList" resultMap="userResultMap">
select * from mybatis.user;
</select>
6. 日志
6.1 maybatis日志工场
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
log信息
6.2 LOG4J
什么是LOG4J?
Log4j是Apache的一个开源项目
-
我们也可以控制每一条日志的输出格式;
-
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
-
可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
使用LOG4G
1.先导包
<!--pom.xml-->
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
2.配置log4j log4j.properties文件
### set log levels ###
log4j.rootLogger = DEBUG,Console,File
### 输出到控制台 ###
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern= %d{ABSOLUTE} %5p %c{1}:%L - %m%n
### 输出到日志文件 ###
log4j.appender.File=org.apache.log4j.RollingFileAppender
log4j.appender.File.File=${project}/WEB-INF/logs/app.log
log4j.appender.File.DatePattern=_yyyyMMdd'.log'
log4j.appender.File.MaxFileSize=10MB
log4j.appender.File.Threshold=ALL
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n
-
设置mybatis中的settings
<!--mybatis-confi.xml--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
-
测试和使用(记住导入的包要apache.log4j.Logger)
static Logger logger = Logger.getLogger(User.class); @Test public void testLogger(){ logger.info("进入了testdebug中"); }
7. 分页
使用分页的原因:
- 提升用户体验
- 减少查询数据量
分页sql
7.1.使用Mybatis实现分页
UserMapper中定义
<select id="getLimitList" resultMap="userResultMap">
select * from mybatis.user limit #{startIndex}, #{pageSize}
</select>
test测试
@Test
public void getLimitList(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String,Integer> map = new HashMap<String, Integer>();
map.put("startIndex", 0);
map.put("pageSize", 2);
List<User> list = userMapper.getLimitList(map);
for (User user : list) {
System.out.println(user);
}
sqlSession.close();
}
7.2 RowBounds分页
不在使用SQl实现分页
-
接口
List<User> getUserByRowBounds(Map<String,Integer> map);
-
mapper.xml
<select id="getUserByRowBounds" resultMap="userMap"> select * from mybatis.user; </select>
-
测试
@Test public void getUserByRowBounds(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); RowBounds rowBounds = new RowBounds(0, 2); List<User> list = sqlSession.selectList("com.guo.dao.UserMapper.getUserByRowBounds", null, rowBounds); for (User user : list) { System.out.println(user); } sqlSession.close(); }
7.3 分页插件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2bRiCbpa-1621000778481)(C:\Users\MSI\AppData\Roaming\Typora\typora-user-images\image-20210413102325273.png)]
8.使用注解开发
8.1 面向接口编程
8.2 使用注解开发
-
注解在接口上实现
public interface UserMapper { // 1.获取全部用户数据 @Select("select * from mybatis.user") List<User> getUserList(); }
-
需要在核心位置中绑定接口
<mappers> <mapper class="com.guo.dao.UserMapper"/> </mappers>
-
测试
@Test public void getUserList(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> list = userMapper.getUserList(); for (User user : list) { System.out.println(user); } sqlSession.close(); }
-
结果:
User{id=1, name='狂神说', password='null'} User{id=2, name='guo', password='null'} User{id=10, name='10', password='null'} User{id=12, name='ghl', password='null'}
注意: 注解语句用于处理简单的sql语句,如果碰到结构复杂的语句或者需要使用resultMap的情况时,注解的使用会使得代码愈发复杂
本质:反射机制实现
底层:动态代理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SObM1Qm9-1621000778483)(C:\Users\MSI\AppData\Roaming\Typora\typora-user-images\image-20210413105716489.png)]
mybatis详细执行流程
8.3 CRUD
方法存在多个参数,所有的参数前面必须加上@Param(“id”) 注解
1.设置openSession方法参数为true 以后不用手动提交
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
2.增删改查
-
写接口
-
写注解
@Select("select * from mybatis.user where id = #{uid}") User getUserById(@Param("uid") int id);
-
测试
@Test public void getUserById(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.getUserById(1); System.out.println(user); sqlSession.close(); }
关于@Param()注解
- 基本类型的参数或者String类型需要+此注解
- 引用类型不需要
- 方法存在多个参数,所有的参数前面必须加上@Param("") 注解
9.Lombok
使用步骤
- 在IDEA中安装lombok的插件
- 在项目导入jar包
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
@ExtensionMethod (Experimental, activate manually in plugin settings)
10. 多对一
1.数据库SQL语句
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES ('1', '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) 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;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
测试环境搭建
- 导入Lombok
- 建立实体类
- 建立Mapper接口
- 建立Mapper.xml文件
- 在核心配置文件中绑定注册
- 测试查询能否成功
2.复杂的属性需要单独处理,对象–association 集合–collection
<!-- 1.按照结果嵌套处理 -->
<select id="getStudent2" resultMap="studentTeacher2">
select s.id sid, s.name sname, t.name tname
from student s, teacher t
where s.tid = t.id
</select>
<resultMap id="studentTeacher2" type="student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<association property="teacher" javaType="Teacher">
<result property="name" column="tname" />
</association>
</resultMap>
<!-- 2.思路
查询出所有学生的信息
根据据查询的到的学生的tid寻找对应的老师
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id" />
<result property="name" column="name" />
<!-- 复杂的属性进行单独处理 集合使用collection 对象使用association -->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher" />
</resultMap>
回顾Mysql多对一查询方式
- 联表查询—类似于方案1
- 子查询—类似于方案2
11.一对多
比如:一个老师拥有多个学生
按照结果嵌套处理
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname, t.id tid
from student s, teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid" />
<result property="name" column="tname" />
<!-- 复杂的属性:需要单独处理
javaType=“” 指定属性类型
ofType:指定集合泛型信息
-->
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid= #{id}
</select>
小结:
1.关联-association
2.集合-collection
3.javaType & ofType
javaType-用来指定实体类中给的属性类型
ofType-泛型约束类型
12.动态sql
什么是动态sql:根据不同条件生成不同的sql语句
搭建环境
IF(一般和where一起使用)
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
where标签会帮你进行自动的匹配,当用户只有第二个输入条件正确的时候,会自动的去掉if标签中的and 或 or 关键字来保证sql语句的输入正确性
choose(搭配when、otherwise使用)
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
Set单独使用
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author},
</if>
</set>
where id = #{id}
</update>
使用if标签的时候不用在意if标签是不是最后一个标签,都可以安心加上逗号
所谓的动态sql,本质就是sql语句,只是我们在sql层面去执行一个逻辑代码
if where set choose when
SQL片段
有的时候,我们可能会将一下功能部分抽取出来进行复用
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
使用时:
<include refid="if-title-author"></include>
实现代码的复用
注意事项:
- 最好基于单表进行SQL片段
- 不要存在where标签
Foreach
初始语句
select * from id =1 or id=2 or id=3
简单化
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<foreach collection="list" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
动态SQL就是在拼接SQl语句,我们只要保证他SQL的正确性
小知识点
@SuppressWarnings("all")
//镇压警告(所有)
<!-- 是否开启 经典数据库列名到java驼峰命名转化 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
13、缓存
13.1 一级缓存
一级缓存默认打开
当调用相同的查询语句时,回从缓存中调用,同一个session级有效,也就是从打开session到关闭关系sqlSession。
刷新缓存的方法:
1.手动清理
2.查询不同东西
3.执行增删改的操作刷新缓存
4.查询不同的mapper
13.2 二级缓存
- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个耳机缓存
- 工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的以及缓存中;
- 当前会话关闭,这个会话的对应的一级缓存小时,但是我们想要的时,会话关闭了,一级缓存中的数据会被保存在二级缓存中
- 新的会话查询信息,就可以从二级缓存中获取内容
- 不同的mapper查出的数据放在自己对象的缓存map中
步骤:
1.开启缓存(默认true)
<!-- 显示开启全局缓存 -->
<setting name="cacheEnabled" value="true"/>
2.再要使用的二级缓存的Mapper开启
<cache/>
<select id="selectById" resultType="user" useCache="true">
测试问题:
1.实体类报错没有进行序列化,使用缓存时,mybatis会自动调用serialize()方法,该方法必须要求实体化pojo才能正常调用
13.3 缓存机制、
缓存顺序:
1.先看二级缓存中有没有
2.再看一级缓存有无
3.最后进行数据库的查询,并将其放入缓存中
13.4 自定义缓存-ehcache
1.使用ehcache时,要先导包
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
2.在mapper使用
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
3.ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--
diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
user.home – 用户主目录
user.dir – 用户当前工作目录
java.io.tmpdir – 默认临时文件路径
-->
<diskStore path="java.io.tmpdir/Tmp_EhCache"/>
<!--
defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
-->
<!--
name:缓存名称。
maxElementsInMemory:缓存最大数目
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
overflowToDisk:是否保存到磁盘,当系统宕机时
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
FIFO,first in first out,这个是大家最熟的,先进先出。
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>