【MySQL】思维导图

278次阅读
没有评论

共计 4849 个字符,预计需要花费 13 分钟才能阅读完成。

 

Mysql 知识点

通过下面的图片可以看出,MySQL 基础 语法分为四部分:连接数据库,对数据库的操作,对表中的数据操作,对表操作等等。
【MySQL】思维导图

SQL 知识点

SQL 相关的知识点就多了,SQL 就是对数据库表进行操作,需要掌握的技术知识点就比较多了。
比如:

  • 如何创建表,更新表,删除表,重命名表。
  • 什么是组合查询,什么是子查询等等。
  • 如何过滤检索数据,分组数据,排序检索数据,快速检索数据。
  • 如何使用函数处理数据,SQL 中会用到哪些函数?
  • 还要知道 seclect 查询语句的执行顺序。
  • 还需要知道聚集函数的使用。
  • 联表查询的实现方法。
    【MySQL】思维导图

Mybatis 知识点

包含了

  • 快速入门
  • mybatis 缓存:一级缓存,二级缓存
  • Mapper 代理知识点
  • 映射关系,映射文件介绍
    【MySQL】思维导图
    看上图知道了一级缓存就是基于 sqlSession 的缓存,Mybatis 默认是开启一级缓存的。实现原理就是:通过一个 Map 来实现
    同一个 sqlsession 再次发出相同的 sql,就从缓存中取不走数据库。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。
    与 Spring 整合之后,使用的是 Mappper 代理对应,一级缓存是失效的。为什么呢?因为在同一线程里面两次查询同一数据所使用的 sqlsession 是不相同的。
    二级缓存是基于 Mapper(同一个命名空间)的缓存,Mybaits 的二级缓存是需要自己在配置文件中配置的。查询结果映射的 pojo 需要实现 java.io.serializable 接口,useCache=“false”。
    这就是 mybatis 中一级缓存和二级缓存。面试的时候也会并经常问到,一定要掌握闹牢固。

面试题分享

MySQL 部分

  1. 一千万条数据的表, 如何分页查询

数据量过大的情况下, limit offset 分页会由于扫描数据太多而越往后查询越慢. 可以配合当前页最后一条 ID 进行查询。

SELECT * FROM T WHERE id > #{ID} LIMIT #{LIMIT}。
当然, 这种情况下 ID 必须是有序递增的, 这也是有序 ID 的好处之一。

  1. MySQL 怎么恢复半个月前的数据

需要前期是有定期的备份整个数据库的数据,如果有备份可以通过 binlog 日志进行恢复

  1. MySQL 事务的隔离级别, 分别有什么特点

1. 读未提交(RU): 一个事务还没提交时, 它做的变更就能被别的事务看到.
2. 读提交(RC): 一个事务提交之后, 它做的变更才会被其他事务看到.
3. 可重复读(RR): 一个事务执行过程中看到的数据, 总是跟这个事务在启动时看到的数据是一致的. 当然在可重复读隔离级别下, 未提交变更对其他事务也是不可见的.
4. 串行化(S): 对于同一行记录, 读写都会加锁. 当出现读写锁冲突的时候, 后访问的事务必须等前一个事务执行完成才能继续执行

  1. 唯一索引比普通索引快吗, 为什么?

唯一索引不一定比普通索引快, 还可能慢.

原因是:

1. 查询时, 在未使用 limit 1 的情况下, 在匹配到一条数据后, 唯一索引即返回, 普通索引会继续匹配下一条数据, 发现不匹配后返回. 如此看来唯一索引少了一次匹配, 但实际上这个消耗微乎其微.
2. 更新时, 这个情况就比较复杂了. 普通索引将记录放到 change buffer 中语句就执行完毕了. 而对唯一索引而言, 它必须要校验唯一性, 因此, 必须将数据页读入内存确定没有冲突, 然后才能继续操作. 对于写多读少的情况, 普通索引利用 change buffer 有效减少了对磁盘的访问次数, 因此普通索引性能要高于唯一索引.

  1. 订单表数据量越来越大导致查询缓慢, 如何处理

分库分表. 由于历史订单使用率并不高, 高频的可能只是近期订单,

因此, 将订单表按照时间进行拆分, 根据数据量的大小考虑按月分表或按年分表.
订单 ID 最好包含时间(如根据雪花算法生成), 此时既能根据订单 ID 直接获取到订单记录, 也能按照时间进行查询.

Mybatis 部分

1.Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?

Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是 一对一,collection 指的就是一对多查询。在 Mybatis 配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
它的原理是: 使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调 用 a.getB().getName(),拦截器 invoke()方法发现 a.getB()是 null 值,那么就会单独发送事先保存好 的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完 成 a.getB().getName()方法的调用。

这就是延迟加载的基本原理。当然了,不光是 Mybatis,几乎所有的包括 Hibernate,支持延迟加载的原理都是一样的。

2.#{}和 ${}的区别

#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理。

Mybatis 在处理 #{}时,#{}传入参数是以字符串传入,会将 SQL 中的#{}替换为? 号,调用
PreparedStatement 的 set 方法来赋值。
#{} 可以有效的防止 SQL 注入提高系统安全性。后者不能防止 SQL 注入 #{} 的变量替换是在 DBMS 中;${} 的变量替换是在 DBMS 外

  1. 使用 MyBatis 的 mapper 接口调用时有哪些要求?

1.Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同。
2.Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相 同。
3.Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同。
4.Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。

  1. Mybatis 如何执行批量操作

使用 foreach 标签
foreach 的主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach 标签的属性主 要有 item,index,collection,open,separator,close。
item 表示集合中每一个元素进行迭代时的别名,随便起的变量名;
index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置,不常用;
open 表示该语句以什么开始,常用“(”;
separator 表示在每次进行迭代之间以什么符号作为分隔符,常用“,”;
close 表示以什么结束,常用“)”。在使用 foreach 的时候最关键的也是最容易出错的就是 collection 属性,该属性是必须指定的,但是 在不同情况下,该属性的值是不一样的,
主要有一下 3 种情况:

  1. 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list
  2. 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为 array
  3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个 Map 了,当然单参数也可以封 装成 map,实际上如果你在传入参数的时候,在 MyBatis 里面也是会把它封装成一个 Map 的,map 的 key 就是参数名

所以这个时候 collection 属性值就是传入的 List 或 array 对象在自己封 装的 map 里面的 key
具体用法如下:

<!-- 批量保存(foreach 插入多条数据两种方法)int addEmpsBatch(@Param("emps") List<Employee> emps); -->
<!-- MySQL 下批量保存,可以 foreach 遍历 mysql 支持 values(),(),()语法 --> // 推荐使用
<insert id="addEmpsBatch">
INSERT INTO emp(ename,gender,email,did) VALUES
<foreach collection="emps" item="emp" separator=","> (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
</foreach>
</insert>
<!-- 这种方式需要数据库连接属性 allowMutiQueries=true 的支持 如 jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true -->
<insert id="addEmpsBatch">
<foreach collection="emps" item="emp" separator=";">
INSERT INTO emp(ename,gender,email,did) VALUES
(#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
</foreach>
</insert>

使用 ExecutorType.BATCH
Mybatis 内置的 ExecutorType 有 3 种,
默认为 simple, 该模式下它为每个语句的执行创建一个 新的预处理语句,单条提交 sql;而 batch 模式重复使用已经预处理的语句,并且批量执行所 有更新语句,显然 batch 性能将更优;但 batch 模式也有自己的问题,比如在 Insert 操作时,在事务没有提交之前,是没有办法获取到自增的 id,这在某型情形下是不符合业务要求的 具体用法如下:
mapper 和 mapper.xml 如下

// 批量保存方法测试
@Test
public void testBatch() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 可以执行批量操作的 sqlSession SqlSession openSession =
sqlSessionFactory.openSession(ExecutorType.BATCH);

// 批量保存执行前时间
long start = System.currentTimeMillis(); try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
for (int i = 0; i < 1000; i++) { mapper.addEmp(new
Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1"));
}

openSession.commit();
long end = System.currentTimeMillis();
// 批量保存执行后的时间 System.out.println("执行时长" + (end - start));
// 批量 预编译 sql 一次==》设置参数==》10000 次==》执行 1 次 677
// 非批量(预编译 = 设置参数 = 执行)==》10000 次 1121
} finally {
openSession.close();
}

mapper 和 mapper.xml 如下

public interface EmployeeMapper {
// 批量保存员工
Long addEmp(Employee employee);
}
<mapper namespace="com.jourwon.mapper.EmployeeMapper"
<!-- 批量保存员工 -->
<insert id="addEmp">
insert into employee(lastName,email,gender) values(#{lastName},#{email},#{gender})
</insert>
</mapper>
本文转载自 CDSN

正文完
 
lucky
版权声明:本站原创文章,由 lucky 2023-01-15发表,共计4849字。
转载说明:转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)