Mybatyis
Mybatis学习笔记
环境:
- JDK1.8
- Mysql5.7
- maven3.6.1
- IDEA
回顾:
- JDBC
- Mysql
- Java基础
- Maven
- Junit
官方文档:
https://mybatis.org/mybatis-3/zh/index.html
1、简介
1.1、什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
如何获取Mybatis:
-
maven仓库
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency>
-
Guthub
1.2、持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(jdbc),io文件持久化
为什么需要持久化?
- 有一些对象,不能丢掉
- 内存太贵了
1.3、持久层
Dao层,Service层,Controller层
- 完成持久化工作的代码块
- 层界限十分明显
1.4、为什么需要Mybatis?
- 方便
- 传统的JDBC代码复杂,简化
- 帮助将数据存入到数据库
优点:
- 简单易学
- 灵活
- sql和代码的分离,提高了可维护性
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组件维护
- 提供xml标签,支持编写动态sql
2、第一个Mybatis程序
思路:搭建环境–>导入Mybatis–>编写代码–>测试
2.1、搭建环境
新建项目
- 新建一个maven项目
- 删除src
- 导包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2.2、创建一个模块
-
编写mybatis的核心配置文件
<?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="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="111"/> </dataSource> </environment> </environments> </configuration>
-
编写mybatis工具类
package com.peng.utils; 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; /** * Company: http://www.abc.com * Author: ASUS * Create Date: 2022/4/4 */ //sqlSessionFactory-->sqlSession public class MybatisUtils { //提升作用域 public static SqlSessionFactory sqlSessionFactory; static{ try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
2.3、编写代码
-
实体类
package com.peng.pojo; /** * Company: http://www.abc.com * Author: ASUS * Create Date: 2022/4/4 */ 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 + '\'' + '}'; } }
-
接口
public interface UserDao { List<User> getUserList(); }
-
接口实现类
<?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命名空间--> <mapper namespace="com.peng.dao.UserDao"> <!-- resultType跟全限定性类名--> <select id="getUserList" resultType="com.peng.pojo.User"> select * from user </select> </mapper>
2.4、测试
注意点
org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource org/mybatis/example/BlogMapper.xml
资源过滤
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
Junit测试
public class UserDaoTest {
@Test
public void test(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
//关闭sqlsession
sqlSession.close();
}
}
3、CRUD
-
接口
public interface UserMapper { List<User> getUserList(); // 根据id查询 User getUserId(int id); // 插入 int addUser(User user); // 修改 int update(User user); // 删除 int delateUser(int id); }
-
接口实现类
<?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"> <mapper namespace="com.peng.dao.UserMapper"> <select id="getUserList" resultType="com.peng.pojo.User"> select * from mybatis.user </select> <select id="getUserId" resultType="com.peng.pojo.User" parameterType="int"> select * from mybatis.user where id = #{id}; </select> <insert id="addUser" parameterType="com.peng.pojo.User"> insert into mybatis.user (id, name, pwd) value (#{id},#{name},#{pwd}); </insert> <update id="update" parameterType="com.peng.pojo.User"> update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id}; </update> <delete id="delateUser" parameterType="com.peng.pojo.User"> delete from mybatis.user where id=#{id}; </delete> </mapper>
-
测试
package com.peng.dao;
import com.peng.pojo.User;
import com.peng.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
/**
* Company: http://www.abc.com
* Author: ASUS
* Create Date: 2022/4/4
*/
public class UserDaoTest {
@Test
public void test(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
//关闭sqlsession
sqlSession.close();
}
// id查询
@Test
public void getUserIdtest(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userId = mapper.getUserId(1);
System.out.println(userId);
//关闭sqlsession
sqlSession.close();
}
// 插入
@Test
public void addUser(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.addUser(new User(5, "彭宇", "123456"));
if (res>0){
System.out.println("插入成功");
}
//提交事务
sqlSession.commit();
//关闭sqlsession
sqlSession.close();
}
// 修改
@Test
public void updateUserTest(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int s = mapper.update(new User(5, "彭", "1111111"));
//提交事务
sqlSession.commit();
//关闭sqlsession
sqlSession.close();
}
// 删除
@Test
public void delateUserTest(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.delateUser(5);
//提交事务
sqlSession.commit();
//关闭sqlsession
sqlSession.close();
}
}
注意增删改需要事务提交
3.1、Map
// Map
int addUser2(Map<String,Object> map);
<insert id="addUser2" parameterType="map">
insert into mybatis.user (id, name, pwd) value (#{userid},#{username},#{userpwd});
</insert>
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("userid",6);
map.put("username","卡哇伊");
map.put("userpwd","22222222222");
mapper.addUser2(map);
sqlSession.commit();
sqlSession.close();
// //获得sqlsession对象
// SqlSession sqlSession = MybatisUtils.getSqlSession();
//
// //执行sql
// UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// //提交事务
// sqlSession.commit();
// //关闭sqlsession
// sqlSession.close();
}
Map传递参数,直接在sql中取出key即可!
对象传递参数,直接在sql中取出对象的属性即可!
只有一个基本类型参数的情况下,可以直接在sql中取到!
4、配置解析
4.1、核心配置文件
mybatis-config.xml
4.2、环境配置
数据库连接:
c3p0、druid、hikari、dbcp
Mybatis默认的事务管理器是JDBC,连接池:POOLED
4.3、属性
properties属性
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?userSSL=true;useUnicode=true;characterEncoding=UTF-8
username=root
password=111
4.4、类型别名(typeAliases)
- 类型别名可为 Java 类型设置一个缩写名字。
- 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
4.5、生命周期和作用域
流程:
具体实现:
这里面的每一个Mapper,就代表一个具体的业务!
5、解决属性名和字段名不一致的问题
5.1、问题:
public class User {
private int id;
private String name;
private String password;//数据库表为pwd
}
解决方法:
起别名
<select id="getUserId" resultType="com.peng.pojo.User" parameterType="int">
select id,name,pwd as password from mybatis.user where id = #{id};
</select>
5.2、resultMap
结果集映射
<resultMap id="userMap" type="user">
<!-- column数据库里面的字段, property实体类中的属性 -->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserId" resultMap="userMap">
select * from mybatis.user where id = #{id};
</select>
该xml文件中不能出现注释中文
resultMap
元素是 MyBatis 中最重要最强大的元素
6、日志
6.1、日志工厂
如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!
曾经:sout、debug
现在:日志工厂!
- SLF4J
- LOG4J(deprecated since 3.5.9) 【掌握】
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING 【掌握】
- NO_LOGGING
在Mybatis中具体使用哪一个日志,在设置中设定!
STDOUT_LOGGING标准日志输出
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
6.2、Log4j
-
导包
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/peng.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
-
配置log4j的实现
<settings> <setting name="logImpl" value="LOG4J"/> </settings>
-
直接测试即可
简单使用:
static Logger logger = Logger.getLogger(UserDaoTest.class);
@Test
public void testlog4j(){
logger.info("info:进入");
logger.debug("debug:");
}
7、分页
代码资源:mybatis-03
7.1、使用Limit分页
select * from mybatis.user limit 3
查询结果为:从0开始,每页3条数据
测试:
-
接口
// 分页 List<User> getUserLimit(Map<String, Integer> map);
-
接口类
<resultMap id="userMap" type="user"> <result column="id" property="id"/> <result column="name" property="name"/> <result column="pwd" property="password"/> </resultMap> <select id="getUserLimit" parameterType="map" resultMap="userMap"> select * from mybatis.user limit #{startIndex},#{pageSize}; </select>
-
测试
// 分页 @Test public void getUserLimit(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Integer> map = new HashMap<String, Integer>(); map.put("startIndex",0); map.put("pageSize",2); List<User> userLimit = mapper.getUserLimit(map); for (User user : userLimit) { System.out.println(user); } sqlSession.close(); }
7.2、RowBounds分页
-
接口
List<User> getUserRowBounds();
-
xml
<select id="getUserRowBounds" parameterType="map" resultMap="userMap"> select * from mybatis.user; </select>
-
测试
// RowBounds @Test public void getUserRowBounds(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); RowBounds rowBounds = new RowBounds(0, 2); Cursor<User> users = sqlSession.selectCursor("com.peng.dao.UserMapper.getUserRowBounds", null, rowBounds); for (User user : users) { System.out.println(user); } sqlSession.close(); }
7.3、分页插件
Mybatis PageHelper网址:https://pagehelper.github.io/
8、注解开发
8.1、面向接口编程
根本原因:解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好*
关于接口的理解
接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。-接口的本身反映了系统设计人员对系统的抽象理解。
接口应有两类:
- 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)
- 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface) ;
一个体有可能有多个抽象面。抽象体与抽象面是有区别的。
8.2、注解式开发
- 编写接口,使用注解
- 配置文件绑定接口
- 测试
8.3、CRUD
代码:mybatis-05
工具类中可以自动提交事务
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
接口
public interface UserMapper {
// 根据id查询@Param注解
@Select("select * from user where id=#{uid}")
User getUserId(@Param("uid") int id);
//插入
@Insert("Insert into user(id,name,pwd) values (id=#{id},name=#{name},pwd=#{password})")
int adduser(User user);
// 修改
@Update("Update user set name=#{name},pwd=#{password} where id=#{id}")
int updateuser(User user);
// 删除
@Delete("Delete from user where id=#{pid}")
int deleteuser(@Param("pid") int id);
}
配置文件添加映射
<mappers>
<mapper class="com.peng.dao.UserMapper"/>
</mappers>
测试
public class UserDaoTest {
static Logger logger = Logger.getLogger(UserDaoTest.class);
// id查询
@Test
public void getUserIdtest(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userId = mapper.getUserId(2);
System.out.println(userId);
//关闭sqlsession
sqlSession.close();
}
//插入
@Test
public void adduser(){
//获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.adduser(new User(6,"卡哇伊","888888"));
//关闭sqlsession
sqlSession.close();
}
}
关于@Param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果只有一个基本类型的话,可以忽略,但是建议大家加上!
- 在sql中引用的就是我们@Param()中设定的属性名!
9、Lombok
- 在IDEA中安装
- 导入jar包
- 在实体类加上注解
10、多对一处理
代码:mybatis-06
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');
10.1、查询嵌套(子查询)
dao层:
接口StudentMapper
public interface StudentMapper {
List<Student> getstudent();
}
接口TeacherMapper
public interface TeacherMapper {
@Select("Select * from teacher where id=#{tid}")
Teacher getTeacherId(@Param("tid") int id);
}
StudentMapper.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">
<mapper namespace="com.peng.dao.StudentMapper">
<select id="getstudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- 复杂的属性,需要单独处理
对象:association
集合:collection-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacherId"/>
</resultMap>
<select id="getTeacherId" resultType="Teacher">
select * from teacher
</select>
</mapper>
10.2、嵌套查询(联表查询)
List<Student> getstudent2();
<select id="getstudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,s.tid tid,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"/>
<result property="id" column="tid"/>
</association>
</resultMap>
11、一对多处理
实体类
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
// 老师的所有学生
private List<Student> students;
}
11.1、查询嵌套
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id=#{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<!-- column="id"为上面传下的老师id给下面学生条件tid查询 -->
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentTeacherId" column="id"/>
</resultMap>
<select id="getStudentTeacherId" resultType="Student">
select * from student where tid=#{tid}
</select>
11.2、结果嵌套查询
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from mybatis.student s,mybatis.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"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
- JavaType 用来指定实体类中属性的类型
- ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类
面试高频:
- Mysql引擎
- InnoDB底层原理
- 索引
- 索引优化!
12、动态 SQL
工具类:随机生成id
public class IDUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
@Test
public void test(){
System.out.println(IDUtils.getId());
}
}
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8
@Data
public class Blog {
private String id;
private String title;
private String author;
private Date create_time;
private int views;
}
public interface BlogMapper {
int addblog(Blog blog);
List<Blog> quaryblog(Map map);
}
<?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">
<mapper namespace="com.peng.dao.BlogMapper">
<insert id="addblog" parameterType="blog">
insert into blog(id,title,author,create_time,views)
values(#{id},#{title},#{author},#{create_time},#{views});
</insert>
<select id="quaryblog" parameterType="map" resultType="blog">
select * from blog where 1=1
<if test="title != null">
and title = #{title}
</if>
</select>
</mapper>
import com.peng.dao.BlogMapper;
import com.peng.pojo.Blog;
import com.peng.utils.IDUtils;
import com.peng.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
* Company: http://www.abc.com
* Author: ASUS
* Create Date: 2022/4/9
*/
public class MyTest {
static Logger logger = Logger.getLogger(MyTest.class);
@Test
public void addblog(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setTitle("Mybatis");
blog.setAuthor("狂神说");
blog.setCreate_time(new Date());
blog.setViews(9999);
mapper.addblog(blog);
blog.setId(IDUtils.getId());
blog.setTitle("Java");
mapper.addblog(blog);
blog.setId(IDUtils.getId());
blog.setTitle("Spring");
mapper.addblog(blog);
blog.setId(IDUtils.getId());
blog.setTitle("微服务");
mapper.addblog(blog);
sqlSession.close();
}
@Test
public void quaryblog(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
List<Blog> blogs = mapper.quaryblog(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setTitle("");
blog.setAuthor("狂神说");
blog.setCreate_time(new Date());
blog.setViews(9999);
mapper.addblog(blog);
sqlSession.close();
}
}
13、缓存
13.1、一级缓存
缓存失效的情况:
-
查询不同的对象
-
增删改操作
-
查询不同的Mapper.xml
-
手动清除缓存
public class MyTest { static Logger logger = Logger.getLogger(MyTest.class); @Test public void getUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); System.out.println(user); sqlSession.clearCache();//手动关闭缓存 sqlSession.close(); } }
小结:一级缓存默认是开启的,只能在一次SqlSession中有效
13.2、二级缓存
-
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
-
基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
-
工作机制
-
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
使用步骤:
1、开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
2、去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
<cache/>
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
3、代码测试
-
所有的实体类先实现序列化接口
public class User implements Serializable { private int id; private String name; private String pwd; }
-
测试代码
@Test public void testQueryUserById(){ SqlSession session = MybatisUtils.getSession(); SqlSession session2 = MybatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); UserMapper mapper2 = session2.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); session.close(); User user2 = mapper2.queryUserById(1); System.out.println(user2); System.out.println(user==user2); session2.close(); }
结论:
- 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
- 查出的数据都会被默认先放在一级缓存中
- 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
13.3、缓存原理
13.4、自定义缓存
导入jar包
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
在mapper.xml使用
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
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="./tmpdir/Tmp_EhCache"/>
<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"/>
<!--
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,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
</ehcache>