diff --git "a/Java\345\237\272\347\241\200.md" "b/Java\345\237\272\347\241\200.md" new file mode 100644 index 0000000..e69de29 diff --git a/MyBatis.md b/MyBatis.md new file mode 100644 index 0000000..1e9e299 --- /dev/null +++ b/MyBatis.md @@ -0,0 +1,1495 @@ +## 1、简介 + +### 1.1 什么时Mybatis + +- MyBatis 是一款优秀的**持久层框架** +- 它支持自定义 SQL、存储过程以及高级映射。 +- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。 +- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。 + +如何获取Mybatis? + +- maven仓库,需要将下面代码置于pom.xml文件中: + + ```xml + + org.mybatis + mybatis + x.x.x + + ``` + +### 1.2 持久化 + +数据持久化 + +- 持久化就是将程序的数据在持久状态和瞬时状态转化过程 +- 内存:断电即失 +- 数据库(jdbc),io文件持久化 +- 生活中的持久化:冷藏、罐头 + +**为什么持久化?** + +- 有些对象,不能丢失 +- 内存珍贵,不能什么都存放在内存中 + +### 1.3 持久层 + +Dao层、Service层、Controller层... + +- 完成持久化工作的代码块 + +### 1.4 为什么需要Mybatis? + +- 帮助程序员将数据存入到数据库中 +- 方便 +- 传统JDBC代码复杂 -> 简化 -> 框架 +- 不用Mybatis也可以,用了更容易上手。 +- 优点: + - 简单易学:没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习 + - 灵活: sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。 + - 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离。sql和代码的分离,提高了可维护性。 + - 提供映射标签,支持对象与数据库的orm字段关系映射 + - 提供对象关系映射标签,支持对象关系组建维护 + - 提供xml标签,支持编写动态sql + +**最重要一点:使用的人多** + +## 2、第一个Mybatis程序 + +思路:搭建环境 --> 导入Mybatis --> 编写代码 --> 测试 + +### 2.1 搭建环境 + +搭建数据库 + +```mysql +create table `user`( +`id` INT(20) NOT NULL PRIMARY KEY, +`name` VARCHAR(30) DEFAULT NULL, +`pwd` VARCHAR(30) DEFAULT NULL +)ENGINE=INNODB DEFAULT CHARSET=utf8; + +insert into `user`(`id`,`name`,`pwd`) values (1,'牛二','123456'),(2,'张三','abcdef'),(3,'李四','987654'); +``` + +新建项目 + +- 创建maven项目 + +- 删除src文件夹 + +- 导入maven等依赖 + + ```xml + + + + mysql + mysql-connector-java + 5.1.40 + + + + org.mybatis + mybatis + 3.5.5 + + + + junit + junit + 4.12 + + + ``` + +### 2.2 创建一个模块 + +**配置核心文件**,在resources中创建mybatis-config.xml + +![image-20200721001618071](img/image-20200721001618071.png) + +```xml + + + + + + + + + + + + + + + + + + +``` + +**编写MyBatis工具类** + +![image-20200721001820172](img/image-20200721001820172.png) + +```java +public class MybatisUtils { + private static SqlsqlSessionFactory sqlsqlSessionFactory; + static{ + try { + //使用mybatis第一步获取sqlsqlSessionFactory对象 + String resource = "mybatis-config.xml"; + InputStream inputStream = Resources.getResourceAsStream(resource); + sqlsqlSessionFactory = new SqlsqlSessionFactoryBuilder().build(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + } + //获取SqlsqlSession连接 + public static SqlsqlSession getsqlSession(){ + return sqlsqlSessionFactory.opensqlSession(); + } + +} +``` + +### 2.3 编写代码 + +**整体架构** + +![image-20200721094904775](img/image-20200721094904775.png) + +**实体类**,对应数据库字段,get/set方法,toString方法 + +```java +public class User { + + private int id; //id + private String name; //姓名 + private String pwd; //密码 + + //构造,有参,无参 + //set/get + //toString() + +} +``` + +**编写Mapper接口类** + +```java +public interface UserMapper { + List getUserList(); +} +``` + +**编写Mapper.xml配置文件(写SQL语句)** + +```xml + + + + + +``` + +- namespace 表示 绑定Dao/Mapper接口 +- id 绑定Mapper中的方法 +- resultType 结果集 一个 +- resultMap 结果集 多个 +- parmeterType 参数类型(下面CRUD中的根据ID查找) + +**编写测试方法** + +```java +public class UserDaoTest { + @Test + public void selectUser() { + SqlsqlSession sqlSession = MybatisUtils.getsqlSession(); + //方法一: + //List users = sqlSession.selectList("com.niu.dao.UserMapper.selectUser"); + //方法二: + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + List users = mapper.getUserList(); + + for (User user: users){ + System.out.println(user); + } + sqlSession.close(); + } +} +``` + +**运行结果** + +![image-20200721094729350](img/image-20200721094729350.png) + +## 3、MyBatis的CRUD + +### 3.1 根据id查询 + +**编写Mapper接口** + +```java +public interface UserMapper { + //获取全部用户 + List getUserList(); + //根据id查询 + User getUserById(int id); +} +``` + +**编写Mapper.xml** + +```xml + +``` + +parameterType 为参数类型 + +**测试用例** + +```java +@Test +public void selectUserById() { + SqlsqlSession sqlSession = MybatisUtils.getsqlSession(); + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + User user = mapper.getUserById(1); + System.out.println(user); + sqlSession.close(); +} +``` + +![image-20200721103712102](img/image-20200721103712102.png) + +### 3.2 增加 + +**** + +**编写Mapper接口** + +```java +//增加 +int addUser(User user); +``` + +**编写Mapper.xml** + +```xml + + insert into user (id,name,pwd) values (#{id},#{name},#{pwd}) + +``` + +**测试用例** + +```java +//增删改需要提交事务 +@Test +public void addUser() { + SqlsqlSession sqlsqlSession = MybatisUtils.getsqlSession(); + UserMapper mapper = sqlsqlSession.getMapper(UserMapper.class); + mapper.addUser(new User(4,"ggg","111")); + sqlsqlSession.commit(); + sqlsqlSession.close(); +} +``` + +![image-20200721105223623](img/image-20200721105223623.png) + +### 3.3 修改 + +**编写Mapper接口** + +```java +//修改 +int updateUser(User user); +``` + +**编写Mapper.xml** + +```xml + + update user set name = #{name},pwd = #{pwd} where id= #{id}; + +``` + +**测试用例** + +```java +//增删改需要提交事务 +@Test +public void updateUser() { + SqlSession sqlSession = MybatisUtils.getSession(); + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + mapper.updateUser(new User(4,"gg","1112")); + sqlSession.commit(); + sqlSession.close(); +} +``` + +### 3.4 删除 + +**编写Mapper接口** + +```java +//删除 +int deleteById(int id); +``` + +**编写Mapper.xml** + +```xml + + delete from user where id = #{id} + +``` + +**测试用例** + +```java +//增删改需要提交事务 +@Test +public void deleteById() { + SqlSession sqlSession = MybatisUtils.getSession(); + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + mapper.deleteById(4); + sqlSession.commit(); + sqlSession.close(); +} +``` + +### 3.5 模糊查询 + +第一种:在Java代码中添加sql通配符 + +```java +string wildcardname = “%smi%”; +list names = mapper.selectlike(wildcardname); + + +``` + +第二种:在sql语句中拼接通配符,会引起sql注入 + +```xml +string wildcardname = “smi”; +list names = mapper.selectlike(wildcardname); + + +``` + +## 4、配置解析 + +4.1 + +MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下: + +- configuration(配置) + - [properties(属性)](https://mybatis.org/mybatis-3/zh/configuration.html#properties) + - [settings(设置)](https://mybatis.org/mybatis-3/zh/configuration.html#settings) + - [typeAliases(类型别名)](https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases) + - [typeHandlers(类型处理器)](https://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers) + - [objectFactory(对象工厂)](https://mybatis.org/mybatis-3/zh/configuration.html#objectFactory) + - [plugins(插件)](https://mybatis.org/mybatis-3/zh/configuration.html#plugins) + - environments(环境配置) + - environment(环境变量) + - transactionManager(事务管理器) + - dataSource(数据源) + - [databaseIdProvider(数据库厂商标识)](https://mybatis.org/mybatis-3/zh/configuration.html#databaseIdProvider) + - [mappers(映射器)](https://mybatis.org/mybatis-3/zh/configuration.html#mappers) + +### 4.2 environment(环境变量) + +MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。 + +**不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。** + +mybatis默认事务管理器 JDBC 连接池:POOLED + +### 4.3 properties(属性) + +可以通过properties属性来实现引用配置文件 + +这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。 + +**编写配置文件db.properties** + +![image-20200721141811040](img/image-20200721141811040.png) + +**引入配置文件** + +![image-20200721142618160](img/image-20200721142618160.png) + +### 4.4 settings(设置) + +**类型别名** + +```xml + + + +不写别名: + +写了: +resultType="user" +``` + +**也可以指定一个包名**,MyBatis 会在包名下面搜索需要的 Java Bean,比如: + +```xml + + + +``` + +pojo下的每个实体类,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。若有注解,则别名为其注解值。 + +```java +@Alias("author") +public class Author { + ... +} +``` + +**开启缓存与懒加载** + +| cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true \|false | true | +| ------------------ | ------------------------------------------------------------ | ------------- | ----- | +| lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 `fetchType` 属性来覆盖该项的开关状态。 | true \| false | false | + +### 4.5 生命周期和作用域 + +![image-20200721144738626](img/image-20200721144738626.png) + +生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的**并发问题**。 + +**SqlSessionFactoryBuilder** + +- 作用在于创建 SqlSessionFactory,创建成功后,就失去了作用 +- **SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域**(也就是局部方法变量) + +**SqlSessionFactory ** + +- 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象 +- 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 +- 最佳作用域是应用作用域 +- 最简单的就是使用单例模式或者静态单例模式 + +**SqlSession** + +- 可以比作连接池里面的一个连接 +- 作用域是请求或方法作用域 +- 用完之后关闭,否者资源被占用 + +![image-20200721145414230](img/image-20200721145414230.png) + +## 5、解决属性名和字段名不一致的问题(resultMap) + +**实体类修改** + +```java +public class User { + private int id; + private String name; + private String password; + .... +} +``` + +测试结果: + +![image-20200721151611858](img/image-20200721151611858.png) + +解决办法: + +- 起别名:select id,name,pwd ad password from user where id = #{id} + +- resultMap 结果集映射 + + ```xml + + + + + + + + + ``` + +## 6、日志 + +### 6.1 日志工厂 + +在db.properties中配置 + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### 6.2 Log4j + +**导入log4j依赖** + +```xml + +log4j +log4j +1.2.17 + +``` + +**创建log4j.properties** + +![image-20200721160054479](img/image-20200721160054479.png) + +**然后百度人家写好的配置文件 复制即可** + +**最后在db.properties的settings日志配置修改** + +```xml + + + +``` + +**Log4j使用** + +![image-20200721161028210](img/image-20200721161028210.png) + +## 7、分页 + +**为什么分页?**减少数据处理量 + +### 7.1 Limit分页 + +```java +语法:SELECT * FROM user LIMIT startIndex,pageSize; +实例:SELECT * FROM user LIMIT 2; #[0,n] +``` + +使用Mybatis实现分页,核心SQL + +1、接口 + +```java +//分页 +List getUserByLimit(Map map); +``` + +2、Mapper.xml + +```xml + +``` + +3、测试 + +```java +@Test +public void getUserByLimit(){ + SqlSession sqlSession = MyBatisUtils.getSession(); + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + HashMap map = new HashMap<>(); + map.put("startIndex",0); + map.put("pageSize",2); + mapper.getUserByLimit(map); +} +``` + +![image-20200721172844988](img/image-20200721172844988.png) + +### 7.2 RowBounds分页 + +1、接口 + +```java +//RowBounds分页 +List getUserByRowBounds(); +``` + +2、mapper.xml + +```xml + +``` + +3、测试 + +```java +@Test +public void getUserByRowBounds(){ + SqlSession sqlsession = MyBatisUtils.getSession(); + //RowBounds实现 + RowBounds rowBounds = new RowBounds(1, 3); + //通过Java代码层实现分页 + List userList = sqlsession.selectList("com.niu.dao.UserMapper.getUserByRowBounds",null,rowBounds); + for (User u : + userList) { + System.out.println(u); + + } +} +``` + +![image-20200721174410484](img/image-20200721174410484.png) + +### 7.3 分页插件-PageHelper + +https://pagehelper.github.io/docs/howtouse/ + +## 8、使用注解开发 + +### 8.1 面向接口编程 + +根本原因: 解耦 + +### 8.2 使用注解开发 + +1.注解在接口上实现 + +```java +@Select("select * from user") +List getUsers(); +``` + +2.核心mybatis配置文件中绑定接口 + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +3.测试使用 + +```java +@Test +public void test(){ + SqlSession sqlSession = MyBatisUtils.getSession(); + //底层主要应用反射 + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + List users = mapper.getUsers(); + for (User user: users + ) { + System.out.println(user); + } + sqlSession.close(); +} +``` + +![image-20200721182151906](img/image-20200721182151906.png) + +本质:反射机制实现 + +底层:动态代理 + +### 8.3 mybatis执行流程 + + + +![image-20200721182708617](img/image-20200721182708617.png) + +### 8.4 注解CRUD + +工具类实现自动提交(查看不用事务提交,但增删改需要) + +```Java +public class MyBatisUtils { + 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(); + } + } + //获取SqlSession连接 并实现自动提交事务 + public static SqlSession getSession(){ + return sqlSessionFactory.openSession(); + } +} +``` + +编写Mapper接口 + +```java +public interface UserMapper { + //查询 + @Select("select * from user") + List getUsers(); + + //方法存在多个参数时使用@Param 且以此注解为主 + @Select("select * from user where id = #{id}") + User getUserById(@Param("id") int id); + @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{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 = #{id}") + int deleteUser(@Param("id") int id); +} +``` + +测试类 + +```java +public class UserMapperTest { + @Test + public void test(){ + SqlSession sqlSession = MyBatisUtils.getSession(); + //底层主要应用反射 + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + //查询 + List users = mapper.getUsers(); + for (User user: users + ) { + System.out.println(user); + } + //按照id查询 + User user = mapper.getUserById(1); + System.out.println(user); + //新增 + mapper.addUser(new User(5,"niuniu","qwe")); + //修改 + mapper.UpdateUser(new User(5,"ntj","ewq")); + //删除 + mapper.deleteUser(7); + sqlSession.close(); + } +} +``` + +注意要在mybatis中绑定接口 + +![image-20200721204124910](img/image-20200721204124910.png) + +XML绑定xml文件 + +![image-20200721204453532](img/image-20200721204453532.png) + +## 9、Lombok + +插件 简便编程 不用写get/set方法 + +## 10、多对一处理 + +多对一的理解: + +- 多个学生对应一个老师 +- 如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师! + +1.数据库设计 + +```mysql +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'); +``` + +2.创建实体类Techer、Student + +3.创建两个Mapper接口 + +4.创建Mapper.xml + +两种方法 通常推荐结果嵌套处理 + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +5.在配置文件中注册绑定Mapper接口 + +6.测试 + +## 11、一对多处理 + +一对多的理解: + +- 一个老师拥有多个学生 +- 如果对于老师这边,就是一个一对多的现象,即从一个老师下面拥有一群学生(集合)! + +与多对一大致相同 + +```xml + + + + + + + + + + + + + + + + + + + + + + + + +``` + +1、关联-association【多对一】 + +2、集合-collection 【一对多】 + +3、所以association是用于一对一和多对一,而collection是用于一对多的关系 + +4、JavaType和ofType都是用来指定对象类型的 + +- JavaType是用来指定pojo中属性的类型 +- ofType指定的是映射到list集合属性中pojo的类型。 + +## 12、动态SQL + +动态SQL:动态SQL就是指根据不同条件生成不同的SQL语句 + +### 12.1 搭建环境 + +数据库 + +```mysql +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 +``` + +创建IDutils类,随机生成id + +```java +public class IDUtil { + + public static String genId(){ + return UUID.randomUUID().toString().replaceAll("-",""); + } +} +``` + +创建实体类 + +```java +public class Blog { + private String id; + private String title; + private String author; + private Date createTime; + private int views; + //set,get.... +} +``` + +创建Mapper接口 + +创建Mapper.XML + +```xml + + + + + +``` + +mybatis核心配置文件,下划线驼峰自动转换 + +```xml + + + + + + + + +``` + +插入初始数据 + +```java +int addBlog(Blog blog); +``` + +sql配置文件 + +编写接口 + +```xml + + insert into blog (id, title, author, create_time, views) + values (#{id},#{title},#{author},#{createTime},#{views}); + +``` + +添加数据 + +```java +@Test +public void addInitBlog(){ + SqlSession session = MyBatisUtils.getSession(); + BlogMapper mapper = session.getMapper(BlogMapper.class); + + Blog blog = new Blog(); + blog.setId(IDUtils.getId()); + blog.setTitle("Mybatis如此简单"); + blog.setAuthor("牛一"); + blog.setCreateTime(new Date()); + blog.setViews(9999); + + mapper.addBlog(blog); + + blog.setId(IDUtils.getId()); + blog.setTitle("Java如此简单"); + blog.setAuthor("牛二"); + mapper.addBlog(blog); + + blog.setId(IDUtils.getId()); + blog.setTitle("Spring如此简单"); + mapper.addBlog(blog); + + blog.setId(IDUtils.getId()); + blog.setTitle("微服务如此简单"); + blog.setAuthor("牛三"); + mapper.addBlog(blog); + + session.close(); +} +``` + +### 12.2 If标签 + +1、编写接口类 + +```java +//需求1 +List queryBlogIf(Map map); +``` + +2、编写SQL语句 + +```xml + + +``` + +3、测试 + +```java +@Test +public void testQueryBlogIf(){ + SqlSession session = MybatisUtils.getSession(); + BlogMapper mapper = session.getMapper(BlogMapper.class); + + HashMap map = new HashMap(); + map.put("title","Mybatis如此简单"); + map.put("author","牛一java"); + List blogs = mapper.queryBlogIf(map); + + System.out.println(blogs); + + session.close(); +} +``` + +这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句! + +### 12.2 where标签 + +```xml + +``` + +### 12.3 set标签(更新) + +1、编写接口方法 + +```java +int updateBlog(Map map); +``` + +2、sql配置文件 + +```xml + + + update blog + + + title = #{title}, + + + author = #{author} + + + where id = #{id}; + +``` + +3、测试 + +```java +@Test +public void testUpdateBlog(){ + SqlSession session = MybatisUtils.getSession(); + BlogMapper mapper = session.getMapper(BlogMapper.class); + + HashMap map = new HashMap(); + map.put("title","动态SQL"); + map.put("author","测试"); + map.put("id","9d6a763f5e1347cebda43e2a32687a77"); + + mapper.updateBlog(map); + + + session.close(); +} +``` + +### 12.4 choose、when、otherwise + +有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。 + +还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员挑选的 Blog)。 + +```xml + +``` + +## 13、缓存(了解) + +### 13.1 简介 + +1、什么是缓存 [ Cache ]? + +- 存在内存中的临时数据。 +- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。 + +2、为什么使用缓存? + +- 减少和数据库的交互次数,减少系统开销,提高系统效率。 + +3、什么样的数据能使用缓存? + +- 经常查询并且不经常改变的数据。 + +### 13.2 Mybatis缓存 + +- MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。 + +- MyBatis系统中默认定义了两级缓存:**一级缓存**和**二级缓存** + +- - 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存) + - 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。 + - 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存 + + + +### 13.3 一级缓存 + +一级缓存也叫本地缓存: + +- 与数据库同一次会话期间查询到的数据会放在本地缓存中。 +- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库; + +```java + @Test + public void test(){ + SqlSession sqlSession = MyBatisUtils.getSession(); + UserMapper mapper = sqlSession.getMapper(UserMapper.class); + User u1 = mapper.queryUserById(1); + System.out.println(u1); + System.out.println("========================="); + User u2 = mapper.queryUserById(1); + System.out.println(u2); + System.out.println(u1==u2); + sqlSession.close(); + } +``` + +![image-20200722213235432](img/image-20200722213235432.png) + +小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭这个区间段。 + +一级缓存的四种失效情况: + +- sqlSession不同 +- 增删改操作,可能会改变原来的数据,所以必定会刷新缓存 +- 查询不同的Mapper.xml +- 手动清理缓存 -> session.clearCache(); + +### 13.4 二级缓存(全局缓存) + +- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存 + +- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存; + +- 工作机制 + +- - 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中; + - 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中; + - 新的会话查询信息,就可以从二级缓存中获取内容; + - 不同的mapper查出的数据会放在自己对应的缓存(map)中; + + + +> 使用步骤 + +1、开启全局缓存 【mybatis-config.xml】 + +``` + +``` + +2、去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】 + +```xml +直接开启 + +官方示例(带参开启) + +这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。 +``` + +3、代码测试 + +- 所有的实体类先实现序列化接口 +- 测试代码 + +```java +@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(); + System.out.println("======="); + User user2 = mapper2.queryUserById(1); + System.out.println(user2); + System.out.println(user==user2); + + session2.close(); +} +``` + +![image-20200722214810692](img/image-20200722214810692.png) + +> 结论 + +- 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据 +- 查出的数据都会被默认先放在一级缓存中 +- 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中 + +### 13.5 缓存原理 + +![image-20200722215839006](img/image-20200722215839006.png) + +![image-20200722220510410](img/image-20200722220510410.png) + +### 13.6 自定义缓存EhCache + +```xml + + org.mybatis.caches + mybatis-ehcache + 1.1.0 + +``` + +在mapper.xml中使用对应的缓存即可 + +``` + + + +``` + +编写ehcache.xml文件,如果在加载时未找到/ehcache.xml资源或出现问题,则将使用默认配置。 + +```xml + + + + + + + + + + + + +``` + diff --git a/img/image-20200721001618071.png b/img/image-20200721001618071.png new file mode 100644 index 0000000..920f0a5 Binary files /dev/null and b/img/image-20200721001618071.png differ diff --git a/img/image-20200721001820172.png b/img/image-20200721001820172.png new file mode 100644 index 0000000..3337e73 Binary files /dev/null and b/img/image-20200721001820172.png differ diff --git a/img/image-20200721094729350.png b/img/image-20200721094729350.png new file mode 100644 index 0000000..eaee0ce Binary files /dev/null and b/img/image-20200721094729350.png differ diff --git a/img/image-20200721094904775.png b/img/image-20200721094904775.png new file mode 100644 index 0000000..a361ef7 Binary files /dev/null and b/img/image-20200721094904775.png differ diff --git a/img/image-20200721103712102.png b/img/image-20200721103712102.png new file mode 100644 index 0000000..9a46964 Binary files /dev/null and b/img/image-20200721103712102.png differ diff --git a/img/image-20200721105223623.png b/img/image-20200721105223623.png new file mode 100644 index 0000000..eed0578 Binary files /dev/null and b/img/image-20200721105223623.png differ diff --git a/img/image-20200721141811040.png b/img/image-20200721141811040.png new file mode 100644 index 0000000..f46c6e4 Binary files /dev/null and b/img/image-20200721141811040.png differ diff --git a/img/image-20200721142618160.png b/img/image-20200721142618160.png new file mode 100644 index 0000000..0649741 Binary files /dev/null and b/img/image-20200721142618160.png differ diff --git a/img/image-20200721144738626.png b/img/image-20200721144738626.png new file mode 100644 index 0000000..a3c1ad6 Binary files /dev/null and b/img/image-20200721144738626.png differ diff --git a/img/image-20200721145414230.png b/img/image-20200721145414230.png new file mode 100644 index 0000000..d96cace Binary files /dev/null and b/img/image-20200721145414230.png differ diff --git a/img/image-20200721151611858.png b/img/image-20200721151611858.png new file mode 100644 index 0000000..60800c0 Binary files /dev/null and b/img/image-20200721151611858.png differ diff --git a/img/image-20200721160054479.png b/img/image-20200721160054479.png new file mode 100644 index 0000000..1a4c628 Binary files /dev/null and b/img/image-20200721160054479.png differ diff --git a/img/image-20200721161028210.png b/img/image-20200721161028210.png new file mode 100644 index 0000000..94d0d50 Binary files /dev/null and b/img/image-20200721161028210.png differ diff --git a/img/image-20200721172844988.png b/img/image-20200721172844988.png new file mode 100644 index 0000000..341035f Binary files /dev/null and b/img/image-20200721172844988.png differ diff --git a/img/image-20200721174410484.png b/img/image-20200721174410484.png new file mode 100644 index 0000000..0cce8a0 Binary files /dev/null and b/img/image-20200721174410484.png differ diff --git a/img/image-20200721182151906.png b/img/image-20200721182151906.png new file mode 100644 index 0000000..0c6b1f1 Binary files /dev/null and b/img/image-20200721182151906.png differ diff --git a/img/image-20200721182708617.png b/img/image-20200721182708617.png new file mode 100644 index 0000000..18ee097 Binary files /dev/null and b/img/image-20200721182708617.png differ diff --git a/img/image-20200721204124910.png b/img/image-20200721204124910.png new file mode 100644 index 0000000..3fa1ab5 Binary files /dev/null and b/img/image-20200721204124910.png differ diff --git a/img/image-20200721204453532.png b/img/image-20200721204453532.png new file mode 100644 index 0000000..2077dfd Binary files /dev/null and b/img/image-20200721204453532.png differ diff --git a/img/image-20200722213235432.png b/img/image-20200722213235432.png new file mode 100644 index 0000000..031adab Binary files /dev/null and b/img/image-20200722213235432.png differ diff --git a/img/image-20200722214801188.png b/img/image-20200722214801188.png new file mode 100644 index 0000000..e81089e Binary files /dev/null and b/img/image-20200722214801188.png differ diff --git a/img/image-20200722214810692.png b/img/image-20200722214810692.png new file mode 100644 index 0000000..e81089e Binary files /dev/null and b/img/image-20200722214810692.png differ diff --git a/img/image-20200722215839006.png b/img/image-20200722215839006.png new file mode 100644 index 0000000..ac3e8e9 Binary files /dev/null and b/img/image-20200722215839006.png differ diff --git a/img/image-20200722220426207.png b/img/image-20200722220426207.png new file mode 100644 index 0000000..03ace7a Binary files /dev/null and b/img/image-20200722220426207.png differ diff --git a/img/image-20200722220510410.png b/img/image-20200722220510410.png new file mode 100644 index 0000000..fc753e0 Binary files /dev/null and b/img/image-20200722220510410.png differ