diff --git "a/48 \351\251\254\345\256\217\350\276\276/\345\244\215\344\271\240.md" "b/48 \351\251\254\345\256\217\350\276\276/\345\244\215\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..9a46e6a65bc1224e813b741d2881dccc83e07e57 --- /dev/null +++ "b/48 \351\251\254\345\256\217\350\276\276/\345\244\215\344\271\240.md" @@ -0,0 +1,311 @@ +数据库 +1.事务 +​ (1)什么是事务? +​ 为了完成某个业务而对数据库进行一系列操作,这些操作要么全部成功,要么全部失败。 +​ (2)事务的四个特性 +原子性:事务包含的这一系列操作,要么全部成功,要么全部失败。 +一致性:事务完成之后,不会将非法的数据写入数据库。 +隔离性:多个事务可以在一定程度上并发执行。 +持久性:事务完成之后,数据要永久保存(一般会保存在硬盘上)。 +原子性(由DBMS的事务管理子系统来实现); +一致性(由DBMS的完整性子系统执行测试任务); +隔离性(由DBMS的并发控制子系统实现); +持久性(由DBMS的恢复管理子系统实现的); +​ (3)隔离级别 +读未提交:一个事务可以读取到另外一个事务尚未提交的数据。该隔离级别可能会产生“脏读”、“不可重复读取”和“幻影读取”问题。 +读已提交:一个事务只能读取到另外一个事务已经提交的数据。该隔离级别解决了“脏读”问题,但是仍然可能会发生“不可重复读取”和“幻影读取”问题。 +可重复读取:在同一个事务当中,多次读取同一份数据,结果一样。该隔离级别解决了“脏读”和“不可重复读取”问题,但是仍然有可能会产生“幻影读取问题”(虚读)。 +序列化:多个同务只能排队执行,即只有一个事务结束之后,另外一个事务才能开始执行。该隔离级别解决了“脏读”,“不可重复读取”和“幻影读取”问题,但是程序性能会下降。所以只有必要的时候(比如在银行系统里面)才会使用。 +总结: +​ 隔离级别从低到高依次是"读未提交"、“读已提交”、“可重复读取”和“序列化”,隔离级别越高,性能越低。mysql数据库默认隔离级别是“可重复读取”,oracle是“读已提交”。数据库底层使用的“加锁”的机制来实现不同的隔离级别,包括对整个表加锁,对表中的行加锁。 +​ mysql数据库开始事务、提交事务、回滚事务 +begin; +commit; +rollback; +1 +2 +3 +​ mysql数据库必须将数据库引擎设置为"innodb"才能支持事务。 +2.视图 +​ (1)什么是视图? +​ 在已有的表或者视图上创建的虚拟表。 +​ (2)创建视图 +​ create view 视图名 as select +注:可以对单表或者多表进行查询,数据库会将视图的定义保存下来。 +可以对(单表)视图进行一些增删改查操作,这些操作会影响到原始的表。 +(3)删除视图 +​ drop view 视图名 +参考sql: +create table t_emp( + id int primary key auto_increment, + name varchar(50), + salary int, + age int +); +create view v_emp as select * from t_emp; +create view v_emp2(name,salary) as select name,salary from t_emp; +insert into v_emp2 values('Jhon',3000); +create table t_dept( + id int primary key, + name varchar(50), + addr varchar(100) +); +insert into t_dept values(100,'财务部','北京'); +insert into t_dept values(200,'开发部','上海'); +create table t_staff( + id int primary key auto_increment, + name varchar(30), + age int, + dept_id int +); +insert into t_staff values(null,'张三',33,100); +insert into t_staff values(null,'李四',23,100); +insert into t_staff values(null,'王五',43,200); +create view v_staff_dept(sname,dname,addr) +as +select s.name sname,d.name dname,d.addr from t_staff s +join t_dept d on s.dept_id = d.id; +drop view v_emp; +3.索引 +(1)什么是索引? +​ 为了提高查询的速度而在数据库端创建的一种排序的数据结构。 +​ 注:索引类似于一本书的目录 +(2)如何创建索引? +​ create index 索引名 on 表名(字段列表) +(3)如何查看当前查询是否用到的索引? +(4) 在哪些字段上加索引? +​ 应该将经常作为查询条件的字段加索引,除此以外,还要在分组、过滤、排序及联合查询的字段上加索引。 +(5)如何删除索引? +​ drop index 索引名 on 表名 +(6)联合索引 +​ 所谓联合索引(复合索引),指的是索引字段是多个,比如: +​ 使用联合索引时,要注意“最左匹配原则”。即在使用联合索引的某个字段作为查询条件时,该字段左边的所有字段也要同时作为查询条件,比如: +​ 联合索引包含了三个字段(c1,c2,c3),则: +​ 将c1,c2,c3同时作为查询条件时,会用到索引; +​ 将c1,c2同时作为查询条件时,会用到索引; +​ 将c1作为查询条件时,会用到索引; +​ 将c2作为查询条件时,不会用到索引; +​ 将c3作为查询条件时,不会用到索引; +​ 将c1和c3作为查询条件时,不会用到索引。 +(7) 索引原理 + 假设t_user表有15条记录,每个磁盘块只能放4条记录,则需要4个磁盘块,对应的"B+" +树结构如下: +(8)主键索引和非主键索引。 +​ 数据库自动会为主键字段添加上相应的索引,该索引称之为主键索引。 +比如,有一张表(id是主键,除此之外还有name,email,age等字段),则数据库会为id字段加上主键索引,如果以id作为条件,显然会用到主键索引,但是如果是以name等非主键字段作为查询条件,则不会用到主键索引,所以为了提高查找的速度,可以在非主键字段上加上相应的索引。 +​ 主键索引和非主键索引有什么区别? +​ 非主键索引叶子节点存放的是索引字段及主键值,而主键索引叶子节点存放的是完整的记录。使用主键索引查找要比使用非主键索引一般要快一些,因为使用非主键索引,很多时候需要“回表”。 +​  什么是索引覆盖? +​  查找的字段都包含在了索引字段里面,此时,不需要进行“回表”操作,查找的速度会非常快。 +面试相关: +​ 为什么数据库不使用B树而是使用B+树? +​ 因为B树索引块除了可以存放索引字段及指针以外,还可以存放记录,也就是说,B树的索引的扇出变少(扇出指的是索引块当中指针的个数),相应的由索引块构成的树的高度增加,也就是说,需要进行更多的“i/o”操作。 + 为什么数据库很少使用hash作为索引的数据结构? +​ hash索引虽然依据索引字段定位记录很快(比B+树还要快),但是不能进行范围查询。 +(9)使用索引需要注意的问题: +​ a. 使用索引之后,虽然加快了查询的速度,但是在进行添加、删除、修改操作时会变慢,因为需要重建索引。在批量添加记录时,建议先临时删除索引,在批量添加成功之后再加上相应的索引。 +​ b.不要建过多的索引。 +​ 注:索引会占用硬盘空间,一般建议不要超过6个。 +​ c.小表不要建索引。 +​ 注:小表使用全表扫描更快。 +​ d.索引字段不要参与计算。 +​ 比如 “select * from t_user where id-1 = 100” 不会用到索引。 +​ 注:包括使用函数都不行。 +​ e. 尽量在同值少的字段上建索引。 +​ 注: 比如性别就不适合作索引。 +​ +4.存储过程(了解) +​ (1)什么是存储过程? +​ 存储在数据库端的一组为了完成特定功能的sql语句。 +​ (2)如何创建存储过程? +​ create procedure 存储过程名([参数]) +​ 参数格式 (参数类型 参数名 数据类型) +​ 参数类型有三种: +​ IN: 输入参数,该参数的值必须在调用该存储过程时指定,在存储过程内部使用, 不能返回。 +​ 缺省值是IN。 +​ OUT:输出参数,该参数值的值可以在存储过程内部修改,并可返回。 +​ INOUT:输入输出参数,该参数需要在调用时指定,并且可以返回。 +delimiter // +create procedure proc_find1() +begin + select * from t_emp; +end +// +delimiter ; +注: + delimiter // 这句的作用是将结束符号设置为"//" +call proc_find1; +delimiter // +create procedure proc_find2(eid int) +begin + select * from t_emp where id = eid; +end +// +delimiter ; +call proc_find2(1); +delimiter // +create procedure proc_find3(out max_sal int) +begin + select max(salary) into max_sal from t_emp; +end +// +delimiter ; +call proc_find3(@sal); +select @sal +​注意:小海豚SQLyog中对delimiter的识别略有不同,修改结尾符时两个都要写。 +(3)使用jdbc调用存储过程 +public class CallProcdure { + /** + * 调用不带参的存储过程 + */ + public static void test1() { + Connection conn = null; + try { + conn = DBUtil.getConnection(); + CallableStatement cs = + conn.prepareCall("{call proc_find1}"); + ResultSet rs = cs.executeQuery(); + while(rs.next()) { + int id = rs.getInt("id"); + String name = rs.getString("name"); + int salary = rs.getInt("salary"); + int age = rs.getInt("age"); + System.out.println("id:" + id + " name:" + + name + " salary:" + salary + " age:" + age); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + DBUtil.close(conn); + } + + } + + /** + * 调用带输入参数的存储过程 + */ + public static void test2() { + Connection conn = null; + try { + conn = DBUtil.getConnection(); + CallableStatement cs = + conn.prepareCall("{call proc_find2(?)}"); + cs.setInt(1, 1); + ResultSet rs = cs.executeQuery(); + while(rs.next()) { + int id = rs.getInt("id"); + String name = rs.getString("name"); + int salary = rs.getInt("salary"); + int age = rs.getInt("age"); + System.out.println("id:" + id + " name:" + + name + " salary:" + salary + " age:" + age); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + DBUtil.close(conn); + } + + } + + /** + * 调用带输出参数的存储过程 + */ + public static void test3() { + Connection conn = null; + try { + conn = DBUtil.getConnection(); + CallableStatement cs = + conn.prepareCall("{call proc_find3(?)}"); + //输出参数赋值不能用setxxx + cs.registerOutParameter(1, Types.INTEGER); + cs.execute(); + int maxSal = cs.getInt(1); + System.out.println("maxSal:" + maxSal); + } catch (Exception e) { + e.printStackTrace(); + } finally { + DBUtil.close(conn); + } + + } + +插入记录时,要先插入主表中的记录。 +删除记录时,要先删除从表中的记录。 +​ 非空: not null +​ 唯一性:unique +​ 检查(了解): +​ 注:检查约束跟数据库版本有关系,mysql8.0.16之后才支持。 +create table t_check( + id int primary key, + name varchar(50), + salary int check(salary > 0 and salary < 20000) +); +1 +2 +3 +4 +5 +练习:写一个存储过程,将薪水前2的员工信息找出来。 +并且使用jdbc来调用该存储过程。 +delimiter // +create procedure proc_find4() +begin + select * from t_emp order by salary desc limit 2; +end +// +delimiter ; +SQL执行过程: + +1. FROM : 对FROM的左表和右边计算笛卡尔积,生成虚表v1(临时表)。 +2. ON: 对虚表v1进行ON筛选,只有符合join条件的行被保留到虚表v2。  +3. WHERE: 对虚表v2进行where条件的过滤,生成虚表v3。 +4. GROUP BY: 依据group by子句中的列,对虚表v3进行分组操作,生成虚表v4。 +5. HAVING: 对虚表v4使用having进行过滤,生成虚表v5。 +6. SELECT :使用select选择需要的列,生成虚表v6。 +7. DISTINCT:对虚表v6中的记录进行去重,生成虚表v7。 +8. ORDER BY: 对虚表v7中的记录进行排序,生成虚表v8。 +9. LIMIT: 从虚表v8中取出指定条数的记录。 +10. Case表达式(未完待续…) + “新手用where 句子进行条件分支,高手用select 句子进行条件分支" + “新手用having 句子进行过滤,高手用select 句子进行过滤" + Case的最强大功能在于,自定义条件分组显示 + 7.简答题: + 1.如何对数据库查询操作进行优化?(数据量大) + 属于开放性题型–重点:一方面考察数据库知识掌握 ;一方面考察分析问题的能力 + 先去看目前的查询操作是怎么写的,看这些操作的sql语句是否存在大量的嵌套查询,先对sql语句进行优化(能用关联查询的尽量用关联查询) + 查看是否建立索引 +11. 若无,建立索引; +12. 若有,查看下索引建立的正确与否 +13. 索引应该建立在哪些字段上? +14. 为了提高查询性能,通常应该建议在where,goup by,order by 后的字段 +15. 注意:索引在哪些情况下会失效?列举几种情况 + 模糊查询以’%'开头,会导致索引失效 + like ‘_xx%’ —索引有效 + like ‘x_’ – 索引有效 + like ‘%x_’ — 索引失效 + 应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。 + 违背了最左匹配原则 + 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描 + 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。 + 如:select id from t where num/2=100应改为:select id from t where num=100*2 + 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。 + 如:select id from t where substring(name,1,3)=’abc’ ,name以abc开头的id应改为: select id from t where name like ‘abc%’ + 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 +16. 索引的原理是什么? + ​ 采用B+树实现 +17. 什么操作会自动给字段加索引? + 添加主键 + 添加外键 + 添加唯一性约束也会给对应的字段添加索引 +18. 事务: + 什么是事务,事务的特性是什么? + 事务是指对数据库进行操作的最小执行单元,不可再分,要么全都执行成功,全都执行失败! + 特性:ACID + 一致性 + 隔离性 + 持久性 + 原子性 + 数据库中事务的提交和回滚: + 提交:事务中的一系列操作都执行结束,提交,表示事务执行成功 + 回滚:事务中若有步骤执行失败,此时回滚事务,该事务执行失败 diff --git "a/48 \351\251\254\345\256\217\350\276\276/\347\254\224\350\256\26027.md" "b/48 \351\251\254\345\256\217\350\276\276/\347\254\224\350\256\26027.md" new file mode 100644 index 0000000000000000000000000000000000000000..cf75fcea86aa1ed29eaea36d64e5b8d84b104a05 --- /dev/null +++ "b/48 \351\251\254\345\256\217\350\276\276/\347\254\224\350\256\26027.md" @@ -0,0 +1,136 @@ +## 视图概述 + +* 视图是一种 虚拟表 ,本身是 不具有数据 的,占用很少的内存空间,它是 SQL 中的一个重要概念。 + +* 视图建立在已有表的基础上, 视图赖以建立的这些表称为基表。 + + ## 创建视图 + +* 在 CREATE VIEW 语句中嵌入子查询 + +```mysql +CREATE [OR REPLACE] +[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] +VIEW 视图名称 [(字段列表)] +AS 查询语句 +[WITH [CASCADED|LOCAL] CHECK OPTION] +``` + +## 查看视图 + +语法1:查看数据库的表对象、视图对象 + +```mysql +SHOW TABLES; +``` + +语法2:查看视图的结构 + +```mysql +DESC / DESCRIBE 视图名称; + +``` + +存储过程与函数 + +MySQL从5.0版本开始支持存储过程和函数。存储过程和函数能够将复杂的SQL逻辑封装在一起, +应用程 序无须关注存储过程和函数内部复杂的SQL逻辑,而只需要简单地调用存储过程和函数即可。 + +**好处:** + +* 1、简化操作,提高了sql语句的重用性,减少了开发程序员的压力。 +* 2、减少操作过程中的失误,提高效率。 +* 3、减少网络传输量(客户端不需要把所有的 SQL 语句通过网络发给服务器)。 +* 4、减少了 SQL 语句暴露在 网上的风险,也提高了数据查询的安全性。 + +### 2) 分类 + +存储过程的参数类型可以是IN、OUT和INOUT。根据这点分类如下: +1、没有参数(无参数无返回) +2、仅仅带 IN 类型(有参数无返回) +3、仅仅带 OUT 类型(无参数有返回) +4、既带 IN 又带 OUT(有参数有返回) +5、带 INOUT(有参数有返回) +注意:IN、OUT、INOUT 都可以在一个存储过程中带多个。 + +变量、流程控制与游标 +在MySQL数据库的存储过程和函数中,可以使用变量来存储查询或计算的中间结果数据, +或者输出最终的结果数据。 + +```mysql +#查看所有全局变量 +SHOW GLOBAL VARIABLES; +#查看所有会话变量 +SHOW SESSION VARIABLES; +或 +SHOW VARIABLES; +``` + +```mysql +#查看指定的系统变量的值 +SELECT @@global.变量名; +#查看指定的会话变量的值 +SELECT @@session.变量名; +#或者 +SELECT @@变量名; +``` + +## 3. 流程控制 + +* 顺序结构 :程序从上往下依次执行 +* 分支结构 :程序按条件进行选择执行,从两条或多条路径中选择一条执行 +* 循环结构 :程序满足一定条件下,重复执行一组语句 + (if,case,loop,while,repeat) + +### 1) 什么是游标(或光标) + +虽然我们也可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的 +关键字 LIMIT 返回一条记录, 但是,却无法在结果集中像指针一样,向前定位一条记录、向后定位一条记录,或者是随意定位到某一 条记录 ,并对记录的数据进行处理。 + +### 2) 使用游标步骤 + +**第一步,声明游标** + +```mysql +DECLARE cursor_name CURSOR FOR select_statement; +``` + +**第二步,打开游标** + +```mysql +OPEN cursor_name +``` + +**第三步,使用游标(从游标中取得数据)** + +```mysql +FETCH cursor_name INTO var_name [, var_name] ... +``` + +**第四步,关闭游标** + +```mysql +CLOSE cursor_name +``` + +## 1. 触发器概述 + +触发器是由 事件来触发 某个操作,这些事件包括 INSERT 、 UPDATE 、 DELETE 事件。所谓事件就是指用户的动作或者触发某项行为。如果定义了触发程序,当数据库执行这些语句时候,就相当于事件发生 了,就会 自动 激发触发器执行相应的操作。 + +当对数据表中的数据执行插入、更新和删除操作,需要自动执行一些数据库逻辑时,可以使用触发器来实现。 + +## 2. 触发器的创建 + +### 1) 语法 + +```mysql +CREATE TRIGGER 触发器名称 +{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名 +FOR EACH ROW +触发器执行的语句块 +``` + +窗口函数的语法结构是: + +```mysql +函数 OVER([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC])