diff --git a/JVM.md b/JVM.md index 1adf88f..0cbd0ba 100644 --- a/JVM.md +++ b/JVM.md @@ -271,7 +271,7 @@ CMS收集器时HotSpot虚拟机第一款真正意义上的并发收集器,第 - 起始标记:**暂停**所有的其他线程,并记录下直接与root相连的线程的对象,速度很快; - 并发标记:同事开启GC和用户线程,用一个闭包结构去记录可达对象。但在这个阶段,闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以GC线程无法宝成可达性分析的实时性。所以这个算法里会跟踪记录这这发生引用更新的地方。 - 重新标记:重新标记为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分的标记记录,需要暂停所有线程。 -- 并发清除:开启用户线程,同事GC线程开始对位标记的区域做清扫。 +- 并发清除:开启用户线程,同时GC线程开始对位标记的区域做清扫。 ![image-20200707234706905](img/image-20200707234706905.png) @@ -305,7 +305,7 @@ G1收集器在后台维护了一个优先列表,每次根据允许的收集时 ### 09.类加载过程 -类加载过程:**加载->链接->初始化**。接着过程又分为三步:**验证->准备->解析** +类加载过程:**加载->链接->初始化**。连接过程又分为三步:**验证->准备->解析** ![img](img/_11720.png) 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..67ab0f6 --- /dev/null +++ "b/Java\345\237\272\347\241\200.md" @@ -0,0 +1,92 @@ +### JDK1.8新特性 + +![image-20201018164440295](../Interview/upload/image-20201018164440295.png) + + + +### 注解 + +Annotation(注解)是 Java 提供的一种对元程序中元素关联信息和元数据(metadata)的途径 +和方法。Annatation(注解)是一个接口,程序可以通过反射来获取指定程序中元素的 Annotation +对象,然后通过该 Annotation 对象来获取注解中的元数据信息。 + +#### 4 种标准 元注解 + +元注解的作用是负责注解其他注解。 Java5.0 定义了 4 个标准的 meta-annotation 类型,它们被 +用来提供对其它 annotation 类型作说明。 + +##### @Target 修饰的对象范围 + +@Target说明了Annotation所修饰的对象范围: Annotation可被用于 packages、types(类、 +接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数 +和本地变量(如循环变量、catch 参数)。在 Annotation 类型的声明中使用了 target 可更加明晰 +其修饰的目标 + +##### @Retention 定义 被保留的时间长短 + +Retention 定义了该 Annotation 被保留的时间长短:表示需要在什么级别保存注解信息,用于描 +述注解的生命周期(即:被描述的注解在什么范围内有效),取值(RetentionPoicy)由: + +- SOURCE:在源文件中有效(即源文件保留) +- CLASS:在 class 文件中有效(即 class 保留) +- RUNTIME:在运行时有效(即运行时保留) + +##### @Documented 描述-javadoc + +@ Documented 用于描述其它类型的 annotation 应该被作为被标注的程序成员的公共 API,因 +此可以被例如 javadoc 此类的工具文档化。 +@Inherited 阐述了某个被标注的类型是被继承的 +@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一 +个使用了@Inherited 修饰的 annotation 类型被用于一个 class,则这个 annotation 将被用于该 +class 的子类。 + +### 反射机制 + +#### 什么是Java反射机制? + +Java反射机制是在运行状态中,对任意一个类,都能够知道这个类的所有方法和属性;对任意一个对象,都能够调用任意一个方法;这种动态获取以及动态调用对象的方法功能成为Java反射机制。 + +#### 反射机制提供了那些功能? + +- 在运行时判定任意一个对象所属的类 +- 在运行时构造任意一个类的对象 +- 在运行时判定任意一个类所具的成员变量和方法; +- 在运行时调运任意一对象的方法 +- 生成动态代理 + +获得class的几种方式 + +![image-20201007092424214](../Interview/upload/image-20201007092424214.png) + +#### 反射机制的应用场景 + +- 逆向代码,例如反编译 +- 与注解结合的框架 如Retrofit(网络加载) +- 动态生成类框架 Gson + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/Java\345\271\266\345\217\221\347\274\226\347\250\213.md" "b/Java\345\271\266\345\217\221\347\274\226\347\250\213.md" index d4aabbe..6e503b1 100644 --- "a/Java\345\271\266\345\217\221\347\274\226\347\250\213.md" +++ "b/Java\345\271\266\345\217\221\347\274\226\347\250\213.md" @@ -137,7 +137,7 @@ lock.unlock(); 创建线程池 -```jav +```java ExecutorService threadPool = Executors.newFixedThreadPool(3);//corePoolSize=3 threadPool.submit(new Callable<>() { @@ -158,7 +158,7 @@ lock.unlock(); ### 07.说说线程池的核心配置参数是干什么的?应该怎么用? - ```jav + ```java 当我们调用上一节的函数生成fixed线程池的时候 ExecutorService threadPool = Executors.newFixedThreadPool(3); 它的底层执行的代码如下 @@ -306,7 +306,7 @@ volatile+原子性:不能够保证原子性,只有在一些极端情况下 (1)lock指令:volatile保证可见性 -```tex +```text 对volatile修饰的变量,执行写操作的话,JVM会发送一条lock前缀指令给CPU,CPU在计算完后会立即将这个值写回主内存,同时因为MESI缓存一致性协议,所以各个CPU都会对总线进行嗅探,自己本地缓存中的数据是否被修改了。 如果发现被修改了,那么CPU就会将自己的本地缓存数据过期掉,然后从主内存中重新加载最新的数据。 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/MySQL\347\264\242\345\274\225.md" "b/MySQL\347\264\242\345\274\225.md" new file mode 100644 index 0000000..b6dc1f8 --- /dev/null +++ "b/MySQL\347\264\242\345\274\225.md" @@ -0,0 +1,55 @@ +索引是帮助MySQL高效获取数据的排好序的数据结构。 + +### 存储引擎 + +#### MyISAM + +MyISAM存储引擎的索引文件和数据文件是分离的(非聚簇,即索引和数据是分开存储的); + +![image-20201021084421515](http://markdown.xiaonainiu.top/img/image-20201021084421515.png) + +#### InnoDB + +- InnoDB存储引擎的**表数据本身**就是按B+Tree组织的一个**索引文件**(聚簇索引); + +- 聚簇索引-叶节点包含了完整的数据记录 + +- 为什么InnoDB表必须有主键,并推荐使用整型的自增主键? + + InnoDB是按照B+Tree组织的一个索引结构文件,如果没有创建主键,InnoDB会选一个,或者添加一列维护。 + + - 在B+Tree结构中,搜索一个数据时,如下图,比如搜索30时,它会先给15 和56比较,然后与20 49依次比较,所以此时整形的比较效率高速度快; + + ![image-20201021084458617](http://markdown.xiaonainiu.top/img/image-20201021084458617.png) + + - 如果是UUID生成的,则是一串字符串,此时不仅比较速率慢,其次索引还占用磁盘内存。 + + - 如果不是自增的如下 + + ![img](http://markdown.xiaonainiu.top/img/LW59U0SI$79Y71}IIDC_7MH.png) + + ![img](http://markdown.xiaonainiu.top/img/WYIHS586}ZX55%_KZ74WRSS.png) + + 不是递增插入的 导致上面进行分裂 还可能在做树平衡,若递增的话 只会往右增加。 + +- 为什么非主键索引结构的叶子节点存储的是主键值? + + 一致性和节省存储空间 + +### 为什么使用B+Tree索引而不使用Hash索引? + +虽然Hash索引速度很快,但是它不支持范围查找,如: + +```mysql +select * from t where id > 5; +``` + +### 为什么使用B+Tree索引而不使用B-Tree索引? + +- B+Tree每行存储的节点较多,原因如下: + + B-Tree结构中是将数据存储到了节点中,因此每行存的索引就变少了(规定每行存16kb)相应的深度(阶)比B+Tree深,会造成进行IO操作过多,影响性能。 + + + +- 其次B+Tree中的叶子节点存在指针,由于指针的存在,在范围查找时,移动指针即可,而B-Tree不行 \ No newline at end of file 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 diff --git a/upload/image-20201021084421515.png b/upload/image-20201021084421515.png new file mode 100644 index 0000000..2b68206 Binary files /dev/null and b/upload/image-20201021084421515.png differ diff --git a/upload/image-20201021084458617.png b/upload/image-20201021084458617.png new file mode 100644 index 0000000..60065f1 Binary files /dev/null and b/upload/image-20201021084458617.png differ diff --git "a/\346\274\253\347\224\273\357\274\232\344\273\200\344\271\210\346\230\257B+ \346\240\221\357\274\237.md" "b/\346\274\253\347\224\273\357\274\232\344\273\200\344\271\210\346\230\257B+ \346\240\221\357\274\237.md" new file mode 100644 index 0000000..c4dee58 --- /dev/null +++ "b/\346\274\253\347\224\273\357\274\232\344\273\200\344\271\210\346\230\257B+ \346\240\221\357\274\237.md" @@ -0,0 +1,167 @@ +这一次我们来介绍 B+ 树。 + +![img](http://markdown.xiaonainiu.top/img/17a0c4f672b34e668a0cd2eb214c117d_th.png) + +![img](http://markdown.xiaonainiu.top/img/c56155c2131e45b0bf69f9ae6cba056e_th.png) + +![img](http://markdown.xiaonainiu.top/img/164ce3d2504c4d63945e134ca6752a2c_th.png) + +![img](http://markdown.xiaonainiu.top/img/891ad19fb4294e9293fdca83e8e34616_th.png) + +**一个m阶的B树具有如下几个特征:** + +1.根结点至少有两个子女。 + +2.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m + +3.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m + +4.所有的叶子结点都位于同一层。 + +5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。 + +![img](http://markdown.xiaonainiu.top/img/eb790f08a02a4bcbbc7cf3f3f8a95d4d_th.png) + +**一个m阶的B+树具有如下几个特征:** + +1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。 + +2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。 + +3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。 + +![img](http://markdown.xiaonainiu.top/img/ff571cfd72ab4a068ce0867b0e450de8_th.png) + +![img](http://markdown.xiaonainiu.top/img/d4430eb5e5ef42008b1facec51636dbb_th.png) + +![img](http://markdown.xiaonainiu.top/img/358025867be14bb99bf8806b98e774d9_th.png) + +![img](http://markdown.xiaonainiu.top/img/034a86d6e1d94c798e63ab144955c0f6_th.png) + +![img](http://markdown.xiaonainiu.top/img/86f732dd90b74be3bf9494859fa78d66_th.png) + +![img](http://markdown.xiaonainiu.top/img/0611ff5a5103461e843ab627f8821419_th.png) + +![img](http://markdown.xiaonainiu.top/img/adada4999fdd48d4937f5f14c0eb7792_th.png) + +![img](http://markdown.xiaonainiu.top/img/afffda21578b4d8a90cbdea4976fb5b6_th.png) + +![img](http://markdown.xiaonainiu.top/img/29583d49358e41fa9c2fbc5169fb7d14_th.png) + +![img](http://markdown.xiaonainiu.top/img/04eb120cd1e04d3a94c2482abc7deb96_th.png) + +![img](http://markdown.xiaonainiu.top/img/3ce28ba0a2bd426ebebac9603f728603_th.png) + +![img](http://markdown.xiaonainiu.top/img/3bd2b4220a0f4d1887e2943a729c40a1_th.png) + +![img](http://markdown.xiaonainiu.top/img/664e36a4da0f45fcaf6e18b68d36a0b4_th.png) + +![img](http://markdown.xiaonainiu.top/img/514d587fa73746978200aca252837a44_th.png) + +B-树中的卫星数据(Satellite Information): + +![img](http://markdown.xiaonainiu.top/img/36efa69561dc4043a17d550133e13a6c_th.png) + +![img](http://markdown.xiaonainiu.top/img/c3a519a9a9e8456d9be41e69709bafaf_th.png) + +B+树中的卫星数据(Satellite Information): + +![img](http://markdown.xiaonainiu.top/img/d8ae1b14e9bf4b1890146eb803ee9795_th.png) + +需要补充的是,在数据库的聚集索引(Clustered Index)中,叶子节点直接包含卫星数据。在非聚集索引(NonClustered Index)中,叶子节点带有指向卫星数据的指针。 + +![img](http://markdown.xiaonainiu.top/img/7a52624e7add4033bb49c3aa5632a681_th.png) + +![img](http://markdown.xiaonainiu.top/img/0ae1d08ece1e4daeac37361e86b3d6a6_th.png) + +![img](http://markdown.xiaonainiu.top/img/32ad0e6237624d718bb9a5346e37792e_th.png) + +第一次磁盘IO: + +![img](http://markdown.xiaonainiu.top/img/6808907785b84be09d8c6b7c8acb5d2a_th.png) + +第二次磁盘IO: + +![img](http://markdown.xiaonainiu.top/img/0193eedf3a5b47129340e2b6c654ef72_th.png) + +第三次磁盘IO: + +![img](http://markdown.xiaonainiu.top/img/68553d369a304d798116f432247c6e3f_th.png) + +![img](http://markdown.xiaonainiu.top/img/3830300c15bf41f8a2c8fdf8d163fa5b_th.png) + +![img](http://markdown.xiaonainiu.top/img/baaed98d8fca4fb9806400651953f92d_th.png) + +![img](http://markdown.xiaonainiu.top/img/99d5067451ec486dbccc37611ff3747c_th.png) + +![img](http://markdown.xiaonainiu.top/img/7522d2811b5340a7a9b222bc14ba7276_th.png) + +![img](http://markdown.xiaonainiu.top/img/169def080e8e47a68fc4fdce3451337a_th.png) + +![img](http://markdown.xiaonainiu.top/img/8db1bc52ab2c418eb9a92fbb1189db98_th.png) + +**B-树的范围查找过程** + +自顶向下,查找到范围的下限(3): + +![img](http://markdown.xiaonainiu.top/img/bb40b700247c425f9b9d358c726d5e65_th.png) + +中序遍历到元素6: + +![img](http://markdown.xiaonainiu.top/img/244ea6eaee4a4e1d87a33967ff6ef5ff_th.png) + +中序遍历到元素8: + +![img](http://markdown.xiaonainiu.top/img/61f472a56f7840e78de23901cb5e85b2_th.png) + +中序遍历到元素9: + +![img](http://markdown.xiaonainiu.top/img/a7881e1683a8486fa3956d585a97bd6d_th.png) + +中序遍历到元素11,遍历结束: + +![img](http://markdown.xiaonainiu.top/img/c3fc3c097cf94d439c5d6962d2fb8d4e_th.png) + +![img](http://markdown.xiaonainiu.top/img/1a3c8f93be3249d28b0813f9d0d5e998_th.png) + +![img](http://markdown.xiaonainiu.top/img/80eff1a11cf24458a5cf80b821d365cd_th.png) + +**B+树的范围查找过程** + +自顶向下,查找到范围的下限(3): + +![img](http://markdown.xiaonainiu.top/img/c0ef4d22cedf43cc8d21732d27f9be3e_th.png) + +通过链表指针,遍历到元素6, 8: + +![img](http://markdown.xiaonainiu.top/img/005777d81ab247c281f8a1b4bc6b3461_th.png) + +通过链表指针,遍历到元素9, 11,遍历结束: + +![img](http://markdown.xiaonainiu.top/img/e972e47b2c554f789e02e90b26a8b543_th.png) + +![img](http://markdown.xiaonainiu.top/img/fb9ce5eba2f845c7b378da1921029511_th.png) + +![img](http://markdown.xiaonainiu.top/img/0ba5c259843a4d0e8ef5d318362f097f_th.png) + +![img](http://markdown.xiaonainiu.top/img/44cd141ed5094c09a1870d0449f9aab7_th.png) + +![img](http://markdown.xiaonainiu.top/img/9b5530015b324841a570505798c937f4_th.png) + +**B+树的特征:** + +1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。 + +2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。 + +3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。 + +**B+树的优势:** + +1.单一节点存储更多的元素,使得查询的IO次数更少。 + +2.所有查询都要查找到叶子节点,查询性能稳定。 + +3.所有叶子节点形成有序链表,便于范围查询。 + +![image-20200922183226827](http://markdown.xiaonainiu.top/img/image-20200922183226827.png) \ No newline at end of file diff --git "a/\346\274\253\347\224\273\357\274\232\344\273\200\344\271\210\346\230\257B-\346\240\221\357\274\237.md" "b/\346\274\253\347\224\273\357\274\232\344\273\200\344\271\210\346\230\257B-\346\240\221\357\274\237.md" new file mode 100644 index 0000000..21dc252 --- /dev/null +++ "b/\346\274\253\347\224\273\357\274\232\344\273\200\344\271\210\346\230\257B-\346\240\221\357\274\237.md" @@ -0,0 +1,523 @@ +# 漫画:什么是B-树? + +![img](http://markdown.xiaonainiu.top/img/168232b112e3cafd) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b112fb1628) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b11318c5d4) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1128d012e) + + + + + +———————————— + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b114f8819c) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1145a551f) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b12e859001) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b130a34232) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b12ecdc411) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b13a49fa47) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1341bb1fb) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b14cbca364) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b14e154a13) + + + + + +———————————— + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b15067d88a) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b15245db58) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b152df328c) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b171b42864) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1748c4597) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1756d0c10) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b184a201db) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b18c28e01c) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b193207a94) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b195001de4) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b196b835b1) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1a5d58f0c) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1abfdfc89) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1ade5fc24) + + + + + +二叉查找树的结构: + + + +![img](http://markdown.xiaonainiu.top/img/168232b1b26bf2e8) + + + + + +第1次磁盘IO: + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1bc8f309b) + + + + + +第2次磁盘IO: + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1c828bb63) + + + + + +第3次磁盘IO: + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1cd0ac5f1) + + + + + +第4次磁盘IO: + + + +![img](http://markdown.xiaonainiu.top/img/168232b1cdc4983f) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1cf06b36f) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1d2bbfb75) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1d6649627) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1e51dbcf6) + +下面来具体介绍一下B-树(Balance Tree),一个m阶的B树具有如下几个特征: + + + +![image-20200922205720555](F:/Typora/Typora/upload/image-20200922205720555.png) + +上图为3阶梯B树(阶数:(Order)阶定义为一个节点的子节点数目的最大值。(自带最大值属性)) + +至多有3颗子树,至多有2个关键字 + +1.根结点至少有两个子女。 + + + +2.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m + + + +3.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m + + + +4.所有的叶子结点都位于同一层。 + + + +5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。 + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1ea6b615c) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1eab1116e) + + + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1eb401c01) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1ec199d2f) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b1f3d365da) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2001c6b90) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b203a7f6f2) + + + + + +第1次磁盘IO: + + + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2028426a1) + + + + + +在内存中定位(和9比较): + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b20712252c) + + + + + +第2次磁盘IO: + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b21ab39190) + + + + + +在内存中定位(和2,6比较): + + + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b21f1f6280) + + + + + +第3次磁盘IO: + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2210be1d5) + + + + + +在内存中定位(和3,5比较): + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2268e1ef2) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b222b71c31) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b23783a7ec) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b22b83bd29) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b24568925a) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b23cfbaff3) + + + + + +自顶向下查找4的节点位置,发现4应当插入到节点元素3,5之间。 + + + +![img](http://markdown.xiaonainiu.top/img/168232b255827ba3) + + + + + +节点3,5已经是两元素节点,无法再增加。父亲节点 2, 6 也是两元素节点,也无法再增加。根节点9是单元素节点,可以升级为两元素节点。于是**拆分**节点3,5与节点2,6,让根节点9升级为两元素节点4,9。节点6独立为根节点的第二个孩子。 + + + +![img](http://markdown.xiaonainiu.top/img/168232b26e7b69d1) + + + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b27634916b) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b27df23411) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b27eddceca) + + + + + +自顶向下查找元素11的节点位置。 + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b28771232f) + + + + + +删除11后,节点12只有一个孩子,不符合B树规范。因此找出12,13,15三个节点的中位数13,取代节点12,而节点12自身下移成为第一个孩子。(这个过程称为**左旋**) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b28e96f94d) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b295c46fe3) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b299dbe7d1) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2aa8e105f) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2ae791779) + + + + + +![img](http://markdown.xiaonainiu.top/img/168232b2b25747e1) \ No newline at end of file