一、需求调研、需求分析(即应用场景)

        ds:软件的存在就是处理数据的,而我们的数据是存储在所谓的仓库当中的。     

二、框架的设计思想  

        ds:严格来说,mysql数据库中的数据也是存储在一个或多个文件上的。就像我们之前在学习使用javaSE时,使用ObjectOutputStream把java对象序列化,然后放到一个文件当中。我们还布置过一个作业,即使用流的方式对文件中的数据进行增删改查。实际上,以上的操作就是最原始的数据库,只不过这个“数据库”它有点low。

三、体系的组织结构设计(重要组件、模块划分、模块间交互)

数据库:

        英文单词DataBase,简称DB。按照一定格式存储数据的一些文件的组合。

        顾名思义:存储数据的仓库,实际上就是一堆文件。

        这些文件中存储了具有特定格式的数据。

数据库管理系统:

        DataBaseManagement,简称DBMS。

        数据库管理系统是专门用来管理数据库中数据的,

        数据库管理系统可以对数据库当中的数据进行增删改查。

        常见的数据库管理系统:MySQL、Oracle、MS SqlServer、DB2、sybase等….

SQL:结构化查询语言

        程序员需要学习SQL语句,程序员通过编写SQL语句,

        然后DBMS负责执行SQL语句,最终来完成数据库中数据的增删改查操作。

        SQL是一套标准,程序员主要学习的就是SQL语句,

        这个SQL在mysql中可以使用,同时在Oracle中也可以使用,在DB2中也可以使用。

三者之间的关系?

        DBMS–执行–> SQL –操作–> DB

四、工作原理、运行流程

  1. DBMS–>执行–> SQL –操作–> DB:程序员通过编写SQL语句,然后DBMS负责执行SQL语句,最终来完成数据库中数据的增删改查操作。sql运行流程是:编译sql语句,执行sql语句。即DBMS拿到一条sql语句,会先进行SQL语句的编译,不符合语法,编译报错。编译未完成后,才能执行sql语句。
  2. from –> where –> group by –> having –> select –> order by –> limit(排序总是在最后执行!)

    from:从某张表中查询数据,

    where:先经过where条件筛选出有价值的数据。

    group by:对这些有价值的数据进行分组。

    having:分组之后可以使用having继续筛选。

    select:select查询出来。

    order by:最后排序输出!

五、具体1:DQL语句

1、group by having

(1)序言:

  1. 在实际的应用中,可能有这样的需求,需要先进行分组,然后对每一组的数据进行操作。

(2)group by子句:

  1. 案例1:select ename,sal from emp where sal > min(sal);错在哪里? 首先,有因为分组函数在使用的时候必须先分组之后才能使用。其次,有执行顺序:from –> where –> group by –> having –> select –> order by。接着,从执行顺序看,where在执行时还没有分组。最后,所以where后面不能出现分组函数。因此,注意:分组函数在使用的时候必须先进行分组,然后才能用。如果你没有对数据进行分组,整张表默认为一组。
  2. 案例2:select sum(sal) from emp;在哪里?这个没有分组,为啥sum()函数可以用呢?因为select在group by之后执行。从执行顺序看,select在执行时已经完成分组。即使此时你没有对数据进行分组,整张表默认为一组。
  3. 案例3:找出每个工作岗位的工资和?实现思路:按照工作岗位分组,然后对工资求和。select job,sum(sal) from emp group by job;以上这个语句的执行顺序?首先,从emp表中查询数据。然后,根据job字段进行分组。最后,对每一组的数据进行sum(sal)。
  4. 案例4:select ename,job,sum(sal) from emp group by job;在哪里?错在:select后面不能加ename。以上语句在mysql中可以执行,但是毫无意义。以上语句在oracle中执行报错,oracle的语法比mysql的语法严格(mysql的语法相对来说松散一些,不那么严格!)。重点结论:在一条select语句当中,如果有group by语句的话,select后面只能跟:参加分组的字段,以及分组函数,其它的一律不能跟(没有意义,甚至在其它的语法要求比较严格的数据库中会报错)。
  5. 案例5:group by后面跟个字段。找出“每个部门,不同工作岗位”的最高薪资?思路:首先,按照部门进行分组;然后,再按照工作岗位进行分组。技巧:两个字段联合成1个字段看。(两个字段联合分组)。select deptno, job, max(sal) from emp group by deptno, job;

(3)having子句: 

        使用having可以对分完组之后的数据进一步过滤。

        having不能单独使用,having必须和group by联合使用。

        having不能代替where。

  1. 案例1:找出每个部门最高薪资,要求显示最高薪资大于3000的?1

    第一步:找出每个部门最高薪资。思路:按照部门编号分组,求每一组最大值:
                  select deptno,max(sal) from emp group by deptno;
    第二步:要求显示最高薪资大于3000:

                  select deptno,max(sal)  from emp group by deptno having max(sal) > 3000;

  2. 案例2:只能使用group by having,而使用where实现不了的情况:
    找出每个部门平均薪资,要求显示平均薪资高于2500的。

    第一步:找出每个部门平均薪资

    select deptno,avg(sal) from emp group by deptno;

    第二步:要求显示平均薪资高于2500的

    select deptno,avg(sal) from emp group by deptno having avg(sal) > 2500;

2、连接查询

序言

        什么是连接查询?

                从一张表中单独查询,称为单表查询。

                emp表和dept表联合起来查询数据(如:从emp表中取员工名字,从dept表中取部门名字),这种跨表查询(即多张表联合起来查询数据)被称为连接查询。

知识点 

  1. 迪卡尔积
            当两张表进行连接查询时,没有任何条件的限制​​​​​​。结果集:第1张表的记录数 * 第2张表的记录数。例如:select ename,dname from emp, dept;

            ds:两张表连接查询的时候,工作流程永远是这样的:首先,拿第1张表的第1条数据,和第2张表的所有数据进行配对,得到配对成功的两条记录,连成一条长长的记录。其次,以此类推荐,即拿第1张表的第2条记录去和第2张表的所有记录进行配对。

            怎么避免笛卡尔积现象?连接时加连接条件,满足这个条件的两条记录被筛选出来,进行配对,连成一条长长的记录。

    SQL92语法:select e.ename,d.dname from emp e, dept d where e.deptno = d.deptno;

            思考:以上查询语句,最终查询的结果条数是14条,但是匹配的过程中,匹配的次数减少了吗?还是56次,只不过进行了四选一。因此,匹配次数并没有减少。

            注意:通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表的连接次数。

  2. 内连接
    1. 等值连接:select … from a join b on a和b的连接条件 where 筛选条件

      92语法:select e.ename,d.dname from emp e, dept d where e.deptno = d.deptno;

      92的缺点:结构不清晰。表的连接条件和后期进一步筛选的条件,都放到了where后面。

      99语法:select e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;

                   //inner可以省略(带着inner可读性更好!!!一眼就能看出来是内连接)

                   select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno
                   // 条件是等量关系,所以被称为等值连接。

      99优点:结构不清晰。表连接的条件是独立的,连接条件放在on后面。而连接之后,如果还需要进一步筛选,再往后继续添加where。

    2. 非等值连接:条件不是一个等量关系,称为非等值连接。
      案例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
      select e.ename, e.sal, s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;
    3. 自连接:技巧:一张表看做两张表。
      案例:查询员工的上级领导,要求显示员工名和对应的领导名?

      select a.ename as '员工名', b.ename as '领导名' from emp a join emp b on

      a.mgr = b.empno;       
      //条件:员工的领导编号 = 领导的员工编号

  3. 外连接:outer是可以省略的,带着可读性强。
    1. 左外连接(左连接):左边表的记录全查出来。如果右边表没有匹配记录时,补空记录
    2. 右外连接(右连接):右边表的记录全查出来。如果左边表没有匹配记录时,补空记录
    3. 注意:外连接的查询结果条数一定是 >= 内连接的查询结果条数?正确。
  4. 全连接(不讲):a表和b表都是主表,都查出来。极少用,不讲。
  5. 三张表,四张表怎么连接?语法:

    select …

    from a join b on a和b的连接条件

               join c on a/b和c的连接条件

               right join d on a/b/c和d的连接条件

    一条SQL中内连接和外连接可以混合,即都可以出现,随便出现。
    理解:a和b连接完成后的结果集(一条长长的记录),再去和c表连接,…..再和d表连接

    案例1:找出每个员工的部门名称以及工资等级,

    要求显示员工名、部门名、薪资、薪资等级?

    select

          e.ename,e.sal,d.dname,s.grade

    from emp e join dept d on  e.deptno = d.deptno

                       join salgrade s on e.sal between s.losal and s.hisal;

    案例2:找出每个员工的部门名称以及工资等级,还有上级领导,

    要求显示员工名、领导名、部门名、薪资、薪资等级?

    select

          e.ename,e.sal,d.dname,s.grade,l.ename

    from emp e join dept d on  e.deptno = d.deptno

                       join salgrade s on e.sal between s.losal and s.hisal

                       left join emp l on e.mgr = l.empno;

         

3、子查询

序言

        什么是子查询?select语句中嵌套select语句,被嵌套的select语句称为子查询。

        子查询都可以出现在哪里呢?

                select      ..(select).

                from        ..(select).

                where      ..(select).

知识点

  1. where子句中的子查询
    案例:找出比最低工资高的员工姓名和工资?
    思路:
          第一步:查询最低工资是多少。select min(sal) from emp;
          第二步:找出>800的。select ename,sal from emp where sal > 800;
          第三步:合并。select ename,sal from emp where sal > (select min(sal) from emp);

    流程:先执行子查询,再执行主查询。

  2. from子句中的子查询:from后面的子查询,可以将子查询的查询结果当做一张临时表
    案例:找出每个岗位的平均工资的薪资等级。
    第一步:找出每个岗位的平均工资(按照岗位分组求平均值)
            select job,avg(sal) from emp group by job;
    第二步:等级表(s表)
            select * from salgrade; 
    第三步:t表和s表进行表连接,条件:t表avg(sal) between s.losal and s.hisal;
            select 
                t.*, s.grade
            from
                (select job,avg(sal) as avgsal from emp group by job) t
            join
                salgrade s
            on
                t.avgsal between s.losal and s.hisal;
    注意:克服心理障碍,把以上的查询结果就当做一张真实存在的表t。

    注意:在子查询中使用函数的地方要起别名

  3. select后面出现的子查询(这个内容不需要掌握,了解即可!!!)
    案例:找出每个员工的部门名称,要求显示员工名,部门名?
          select 
            e.ename,e.deptno,(select d.dname from dept d where e.deptno = d.deptno) as dname 
          from 
            emp e;
          //错误:ERROR 1242 (21000): Subquery returns more than 1 row
          select 
            e.ename,e.deptno,(select dname from dept) as dname
          from
            emp e;
        注意:对于select后面的子查询来说,这个子查询只能一次返回1条结果,多于1条,就报错了。!

4、limit:分页查询

        limit作用:将查询结果集的一部分取出来。通常使用在分页查询当中。

        完整用法:limit startIndex, length。

        startIndex是起始下标,length是长度。

        起始下标从0开始。

        缺省用法:limit 5; 这是取前5.

        注意:mysql当中limit在order by之后执行!!!!!!

        记公式:limit (pageNo-1)*pageSize , pageSize

5、其它语法

  1. and、or混用:and和or同时出现,and优先级较高。如果想让or先执行,需要加“小括号”。以后在开发中,如果不确定优先级,就加小括号就行了。
  2. in、or的关系:in表示包含,相当于多个 or。注意:in不是一个区间,in后面跟的是具体的值。
  3. like转义字符:找出名字中有“_”的?select name from t_student where name like '%_%'; //这样不行,应该这样写:mysql> select name from t_student where name like '%\_%'; // \转义字符。

  4. order by 多字段:select ename,sal from emp order by sal asc, ename asc; // sal在前,起主导,只有sal相等的时候,才会考虑启用ename(所以可能用不上)排序。

  5. null的理解:null不是一个值,null是什么也没有。

  6. 单行处理函数与多行处理(分组)函数有区别:单行处理函数的特点:一个输入(一行记录)对应一个输出。和单行处理函数相对的是:多行处理函数。(多行处理函数特点:多个输入,对应1个输出!)

  7. 单行处理函数finull、null参与的运算:注意:NULL只要参与运算,最终结果一定是NULL。为了避免这个现象,需要使用ifnull函数。ifnull函数用法:ifnull(数据, 被当做哪个值)。

  8. 单行处理函数case..when..then..when..then..else..end:当员工的工作岗位是MANAGER的时候,工资上调10%,当工作岗位是SALESMAN的时候,工资上调50%,其它正常。(注意:不修改数据库,只是将查询结果显示为工资上调)

    select ename,job, sal as oldsal,

    (case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 else sal end) as newsal

    from emp;

  9. 多行处理(分组)函数与分组的关系:(1)分组函数在使用的时候必须先进行分组,然后才能用。如果你没有对数据进行分组,整张表默认为一组。

  10. 多行处理(分组)函数使用注意事项:(1)分组函数自动忽略NULL,你不需要提前对NULL进行处理。(2)分组函数中count(*)和count(具体字段)有什么区别?count(具体字段):表示统计该字段下所有不为NULL的元素的总数。count(*):统计表当中的总行数。(只要有一行数据count则++)因为每一行记录不可能都为NULL,一行数据中有一列不为NULL,则这行数据就是有效的。(3)分组函数不能够直接使用在where子句中。(4)所有的分组函数可以组合起来一起用。

  11. distinct最前方:select ename,distinct job from emp,这样编写是错误的,语法错误。(1)distinct只能出现在所有字段的最前方。(2)distinct出现在job,deptno两个字段之前,表示两个字段联合起来去重,如 select distinct job,deptno from emp。(3)以下是正确的:统计一下工作岗位的数量?select count(distinct job) from emp;

  12. union。(1)union在进行结果集合并的时候,要求两个结果集的列数相同。(2)MYSQL可以,但oracle语法严格 ,不可以,报错。oracle中要求:结果集合并时列和列的数据类型也要一致。

六、具体2:关于mysql中的数据类型?

1、很多数据类型,我们只需要掌握一些常见的数据类型即可。

  1.  varchar(最长255)
    1. 可变长度的字符串        
    2. 比较智能,节省空间。
    3. 会根据实际的数据长度动态分配空间。
    4. 优点:节省空间
    5. 缺点:需要动态分配空间,速度慢。
  2. char(最长255)
    1. 定长字符串
    2. 不管实际的数据长度是多少。
    3. 分配固定长度的空间去存储数据。
    4. 使用不恰当的时候,可能会导致空间的浪费。
    5. 优点:不需要动态分配空间,速度快。
    6. 缺点:使用不当可能会导致空间的浪费。
  3. varchar和char我们应该怎么选择?
    1. 性别字段你选什么?因为性别是固定长度的字符串,所以选择char。
    2. 姓名字段你选什么?每一个人的名字长度不同,所以选择varchar。
  4. int(最长11):数字中的整数型。等同于java的int。
  5. bigint:数字中的长整型。等同于java中的long。
  6. float :单精度浮点型数据
  7. double:双精度浮点型数据
  8. date:短日期类型
  9. datetime:长日期类型
  10. clob
    1. 字符大对象        
    2. 最多可以存储4G的字符串。
    3. 比如:存储一篇文章,存储一个说明。
    4. 超过255个字符的都要采用CLOB字符大对象来存储。
    5. Character Large OBject:CLOB
  11. blob
    1. 二进制大对象
    2. Binary Large OBject
    3. 专门用来存储图片、声音、视频等流媒体数据。
    4. 往BLOB类型的字段上插入数据的时候,例如插入一个图片、视频等,
    5. 你需要使用IO流才行。

2、时间类型与字符串类型的转换:

        mysql的日期格式:

                %Y 年

                %m 月

                %d 日

                %h 时

                %i 分

                %s 秒

        mysql短日期默认格式:date:%Y-%m-%d

        mysql长日期默认格式:dateTime:%Y-%m-%d %h:%i:%s

        drop table if exists t_user;

        create table t_user(

                id int,

                name varchar(32),

                birth date,

                create_time datetime

        );

str_to_date('字符串日期', '日期格式')。将字符串varchar类型转换成date类型。

//  insert插入日期  

insert into t_user(id,name,birth) values(1, 'zhangsan', str_to_date('01-10-1990','%d-%m-%Y'));

//  (自动数据类型转换)即自动将insert语句中的字符串转换为日期类型date

insert into t_user(id,name,birth) values(2, 'lisi', '1990-10-01');

date_format(日期类型数据, '日期格式'):将date类型转换成具有一定格式的varchar字符串类型。

//   select日期类型的数据

select id,name,date_format(birth,'%Y/%m/%d') as birth from t_user;

//  以下,的SQL语句实际上是进行了默认的日期格式化,自动将数据库中的date类型转换成varchar类型(自动数据类型转换)。并且采用的格式是mysql默认的日期格式:'%Y-%m-%d'

select id,name,birth from t_user;

3、date和datetime两个类型的区别?

        date是短日期:只包括年月日信息。

        datetime是长日期:包括年月日时分秒信息。

        mysql短日期默认格式:%Y-%m-%d

        mysql长日期默认格式:%Y-%m-%d %h:%i:%s

        drop table if exists t_user;

        create table t_user(

                id int,

                name varchar(32),

                birth date,

                create_time datetime

        );

   insert into t_user(id,name,birth,create_time) values(1,'zhangsan','1990-10-01','2020-03-18 15:49:50');

        //  在mysql当中怎么获取系统当前时间?now() 函数,并且获取的时间带有:时分秒信息!!!!是datetime类型的。

        insert into t_user(id,name,birth,create_time) values(2,'lisi','1991-10-01',now());

七、具体3:DDL语句

1、create语句

        创建一个学生表?

        学号、姓名、年龄、性别、邮箱地址

        create table t_student(

                no int, //  int这里写也得不写也得,写也就是给个建议长度,超过也没问题

                name varchar(32),

                sex char(1) default 'm',

                age int(3),

                email varchar(255)

        );

        //  快速建表      表创建出来,同时表中的数据也存在了!!!

        create table emp2 as select * from emp;

        create table mytable as select empno,ename from emp where job = 'MANAGER';

        

2、drop语句:

        drop table t_student; // 当这张表不存在的时候会报错!

        drop table if exists t_student;// 如果这张表存在的话,删除

3、alert(建议使用工具!!!)

        添加一个字段,删除一个字段,修改一个字段!!!

八、具体4:DML语句

1、insert

        insert into 表名(字段名1,字段名2,字段名3…) values(值1,值2,值3);

        注意:字段名和值要一一对应。什么是一一对应?数量要对应。数据类型要对应。

        注意:没有给其它字段指定值的话,默认值是NULL。或者使用default,给出默认值。

        注意:前面的字段名省略的话,等于都写上了!所以值也要都写上!

        //  可以一次插入多条记录。

        insert into t_user(id,name,birth,create_time) values

        (1,'zs','1980-10-11',now()),

        (2,'lisi','1981-10-11',now()),

        (3,'wangwu','1982-10-11',now());

        //  快速插入数据

        insert into dept_bak select * from dept; //很少用!

2、update

        update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3… where 条件;

        注意:没有条件限制会导致所有数据全部更新。

3、delete

        delete from 表名 where 条件;

        注意:没有条件,整张表的数据会全部删除!

4、truncate

     // 快速删除表中的数据

     delete from dept_bak; //这种删除数据的方式比较慢。可恢复(回滚)。

     truncate table dept_bak;// 快、不可恢复(回滚)。

九、具体5:性能与优化

  1. 连接查询时关联的表越多,匹配次数越多,查询效率越低。
    优化策略:首先,减少关联的表的数量。其次,通过条件减少表连接记录之间匹配的次数,例如,可以通过where条件对某一张表的数据进行过滤再和另一张表进行连接。
  2. select * from tablename:这种方式的缺点:(1)效率低(底层会把*号转换为表的全部字段);(2)可读性差。在实际开发中不建议,可以自己玩没问题。

    优化策略:可以把每个字段都写上,如select a,b,c,d,e,f… from tablename;

  3. 案例1:找出每个部门最高薪资,要求显示最高薪资大于3000的?

    第一步:找出每个部门最高薪资。思路:按照部门编号分组,求每一组最大值:
                  select deptno,max(sal) from emp group by deptno;
    第二步:要求显示最高薪资大于3000:
                  select deptno,max(sal)  from emp group by deptno having max(sal) > 3000;

    思考:提出问题,以上的sql语句执行效率是不是低?比较低。

    思路:实际上可以这样考虑:先将大于3000的都找出来,然后再分组。

    高效:select  deptno,max(sal) from emp where sal > 3000 group by deptno;

    优化策略:能先用where过滤掉的,就先使用where过滤掉。where和having,优先选择where。where实在完成不了,再进行分组并使用having。

  4. select ename,dname from emp, dept where emp.deptno = dept.deptno;
    效率很低,因为select ename,dname中的ename,dname都有可能会去emp, dept中去查找。
    优化策略:我们可以指明ename,dname分别到哪张表中去查找:
    select emp.ename,dept.dname from emp, dept where emp.deptno = dept.deptno;

  5. 案例:查询工作岗位是MANAGER和SALESMAN的员工?
    方案1:select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN';
    方案2:select ename,job from emp where job in('MANAGER','SALESMAN');
    方案3:select ename,job from emp where job = 'MANAGER'
                    union
                 select ename,job from emp where job = 'SALESMAN';
    结论:union效率要高一些。
    优化策略:union的效率要高一些。对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。而union可以做到减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。使用union的话是:100次 + 100次 = 200次,即union把乘法变成了加法运算。

  6. delete语句删除数据的原理?(delete属于DML语句!!!)

       表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放!!!

       这种删除缺点是:删除效率比较低。

       这种删除优点是:支持回滚,后悔了可以再恢复数据!!!

    truncate语句删除数据的原理?

       这种删除效率比较高,表被一次截断,物理删除。

       这种删除缺点:不支持回滚。

       这种删除优点:快速。

    大表非常大,上亿条记录????

       删除的时候,使用delete,也许需要执行1个小时才能删除完!效率较低。

       可以选择使用truncate删除表中的数据。只需要不到1秒钟的时间就删除结束。效率较高。

十、具体6:事务

1 生活问题

        正是因为做某件事的时候,需要多条DML语句共同联合起来才能完成,所以需要事务的存在。如果任何一件复杂的事儿都能一条DML语句搞定,那么事务则没有存在的价值了。

2解决方案

(1)思想 

  1. 一个事务其实就是一个完整的业务逻辑。

(2)流原:事务是怎么做到多条DML语句同时成功和同时失败的呢?

  1. InnoDB存储引擎:提供一组用来记录事务性活动的日志文件。

  2. 在事务的执行过程中,每一条DML的操作都会记录到“事务性活动的日志文件”中。

  3. 事务开启

  4. 提交事务?

    1. 清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。

    2. 提交事务标志着,事务的结束。并且是一种全部成功的结束。

  5. 回滚事务?(roolbak:回滚永远都是只能回滚到上一次的提交点!)

    1. 清空事务性活动的日志文件,并且将之前所有的DML操作全部撤销

    2. 回滚事务标志着,事务的结束。并且是一种全部失败的结束。

(3)mysql事务常用设置 

  1. 只有DML语句才会有事务这一说,其它语句和事务无关!!!
  2. mysql默认情况下是支持自动提交事务的。(自动提交)。
    什么是自动提交?每执行一条DML语句,则提交一次!

    这种自动提交实际上是不符合我们的开发习惯,因为一个业务

    通常是需要多条DML语句共同执行才能完成的,为了保证数据

    的安全,必须要求同时成功之后再提交,所以不能执行一条

    就提交一条。

  3. 怎么将mysql的自动提交机制关闭掉呢?先执行这个命令:start transaction;

(4)事务包括4个特性:ACID

A:原子性

        不可再分。

C:一致性

        在同一个事务当中,所有操作必须同时成功,或者同时失败,以保证前后数据的一致性。

I:隔离性      

  1. 教室A和教室B之间有一道墙,这道墙就是隔离性。
  2. 两个事务同时去操作一张表:A事务在操作一张表的时候,另一个事务B也操作这张表会那样???这就是隔离性。
  3. 相当于多线程并发访问同一张表一样,此时就会有多线程带来的线程安全问题。为了解决事务之间的线程安全问题,就要使用事务的隔离性。
    1. D:持久性

        将数据持久化到硬盘上的数据库中。

(5)重点研究一下事务的隔离性!!!

  1. 事务的隔离级别:A教室和B教室中间有一道墙,这道墙可以很厚,也可以很薄。这道墙越厚,表示隔离级别就越高。

  2. 分类:

    1. 读未提交(最低级别):没有提交就读到了

      1. 原因:事务A可以读取到事务B未提交的数据。

      2. 问题:脏数据,脏读现象

    2. 读已提交:提交之后才能读到数据绝对真实,oracle默认。

      1. 原因:事务A只能读取到事务B提交之后的数据。

      2. 解决:读未提交

      3. 问题:不可重复读

               什么是不可重复读取数据呢?在事务开启之后,第一次读到的数据是3条,当前事务还没有结束,可能第二次再读取的时候,读到的数据是4条,3不等于4称为不可重复读取。

    3. 可重复读:即使提交之后也读不到,永远读取的都是事务A刚开启事务时的数据数据不够真实,出现幻影读。mysql默认。

      1. 原因:事务A开启之后,不管是多久,每一次在事务A中读取到的数据都是一致的。即使事务B将数据已经修改,并且提交了,事务A读取到的数据还是没有发生改变,这就是可重复读。

      2. 解决:不可重复读

      3. 问题:可以会出现幻影读。每一次读取到的数据都是幻象。不够真实!

      4. 案例:以下需求应该使用什么样的隔离级别?可重复读即可。
        下午1点开始开启了事务,只要事务不结束,到下午3点,读到的数据还是那样!
        原理:就是做了数据的一个备份,或者说对数据进行了一个快照。
        mysql入门基础-dljd-老杜-编程知识网

    4. 序列化/串行化(最高级别):

      1. 原因:事务排队,需要等待其他事务的提交,不能并发!有类似于java中的synchronized,线程同步(事务同步)。

      2. 解决:解决了以上所有问题(读未提交、读已提交、可重复读)

      3. 问题:每一次读取到的数据都是最真实的,并且效率是最低的。

十一、具体7:数据库对象:视图

1、生活问题:通过对视图的操作,会影响到原表数据

2、解决方案

(1)创建视图对象:

        create view dept2_view as select * from dept2;

        注意:只有DQL语句才能以view的形式创建。

                   create view view_name as 后面的语句必须是DQL语句;

(2)删除视图对象:

        drop view dept2_view;

(3)用视图做什么?

        我们可以面向视图对象进行增删改查,对视图对象的增删改查,会导致原表被操作!(视图的特点:通过对视图的操作,会影响到原表数据。)

(4)视图对象在实际开发中到底有什么用?《方便,简化开发,利于维护》

        假设有一条非常复杂的SQL语句,而这条SQL语句需要在不同的位置上反复使用。每一次使用这个sql语句的时候都需要重新编写,很长,很麻烦,怎么办?可以把这条复杂的SQL语句以视图对象的形式新建。在需要编写这条SQL语句的位置直接使用视图对象,可以大大简化开发。并且利于后期的维护,因为修改的时候也只需要修改一个位置就行,只需要修改视图对象所映射的SQL语句。

        我们以后面向视图开发的时候,使用视图的时候可以像使用table一样。可以对视图进行增删改查等操作。视图不是在内存当中,视图对象也是存储在硬盘上的,不会消失。

十二、具体8:数据库对象:索引

1、生活中的问题

  1. 提高查询效率

2、解决方案

(1)思想

  1. 索引相当于一本书的目录(多级)

(2)流原

  1. 索引是在数据库表的字段上添加的。一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。

  2. MySQL在查询方面主要就是两种方式:

    1. 第一种方式:全表扫描

    2. 第二种方式:根据索引检索。

  3. 案例:select * from t_user where name = 'jack';

    1. 以上的这条SQL语句会去name字段上扫描,为什么?因为查询条件是:name='jack'。

      1. 全表(字段)扫描:如果name字段上没有添加索引(目录),或者说没有给name字段创建索引,MySQL会进行全扫描,即会将name字段上的每一个值都比对一遍。效率比较低。

      2. 索引扫描:索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。先通过目录(索引)去定位一个大概的位置,然后直接定位到这个位置,做局域性扫描,缩小扫描的范围,快速的查找。这种查找方式属于通过索引检索,效率较高。

  4. 索引排序:

           在实际中,汉语字典前面的目录是排序的,按照a b c d e f….排序,为什么排序呢?因为只有排序了才会有区间查找这一说!(缩小扫描范围其实就是扫描某个区间罢了!)

           在mysql数据库当中索引也是需要排序的,并且这个所以的排序和TreeSet数据结构相同。TreeSet(TreeMap)底层是一个自平衡的二叉树!在mysql当中索引是一个B-Tree数据结构。
            遵循左小又大原则存放。采用中序遍历方式遍历取数据。

  5. 索引实现原理

mysql入门基础-dljd-老杜-编程知识网

mysql入门基础-dljd-老杜-编程知识网

  1. 第一步:根据左小右大的原则,把索引字段排序到一棵B-Tree上。
  2. 第二步:同时把当前索引字段所在的记录的物理存储编号放在后面,可以理解成是一个map(key=索引字段值,value=当前索引字段所在的记录的物理存储编号)。
  3. 第三步:select * from t_user where id=101;
  4. 第四步:mysql发现id字段上有索引对象,所以会通过索引对象idIndex进行查找。
  5. 第五步:mysql从头节点开始查询,通过左小右大的排序规则在B-Tree树上查找。顺序是:100 > 120 >101,即定位到了101。
  6. 第六步:通过101得出物理编号:0x666。
  7. 第七步:此时马上把sql语句转换为select * from t_user where 物理编号 = 0x666,直接从物理硬盘上拿记录,并返回查询结果。

(3)索引的使用

1)索引分类

  1. 单一索引:一个字段上添加索引。
    1. 主键索引:主键上添加索引。
    2. 唯一性索引:具有unique约束的字段上添加索引。

  2. 复合索引:两个字段或者更多的字段上添加索引。
    1. 复合主键索引
    2. 复合唯一性索引

注意:唯一性比较弱的字段上添加索引用处不大。

2)什么条件下,我们会考虑给字段添加索引呢?

  1. 条件1:数据量庞大
  2. 条件2:这个字段总是被扫描,即该字段经常出现在where的后面,以条件的形式存在。
  3. 条件3:该字段很少变动,该字段很少的DML(insert delete update)操作。(因为DML之后,索引需要重新排序。)
  4. 建议不要随意添加索引,因为索引也是需要维护的,太多的话反而会降低系统的性能。
  5. 建议通过主键查询,建议通过unique约束的字段进行查询,效率是比较高的。

3)索引的创建与删除

        创建索引:

                mysql> create index emp_ename_index on emp(ename);

                给emp表的ename字段添加索引,起名:emp_ename_index

        删除索引:

                mysql> drop index emp_ename_index on emp;

                将emp表上的emp_ename_index索引对象删除。

4)在mysql当中,怎么查看一个SQL语句是否使用了索引进行检索?

mysql入门基础-dljd-老杜-编程知识网

5)索引失效

  1. 失效的第1种情况:like + %

  2. 失效的第2种情况:or

  3. 失效的第4种情况:索引列参加了运算

  4. 失效的第5种情况:索引列使用了函数

  5. 失效的第3种情况:复合索引

    什么是复合索引?

    两个字段,或者更多的字段联合起来添加一个索引,叫做复合索引。

    create index emp_job_sal_index on emp(job,sal);

  6. 失效的第6…

  7. 失效的第7…

6)问题 

mysql入门基础-dljd-老杜-编程知识网

十三、具体9:数据库存储引擎(了解)

1 生活的思想

     mysql入门基础-dljd-老杜-编程知识网 

2 解决方案

(1)思想

  1. 实际上存储引擎是一个表存储/组织数据的方式。

  2. 不同的存储引擎,表存储数据的方式不同。

  3. mysql数据库中,每张表都可以指定存储引擎。表的存储引擎不一样,即表存储数据的方式不一样。

(2)怎么表的存储引擎

        show create table t_student;

(3)怎么给表指定“存储引擎”呢?

        建表时指定存储引擎,以及字符编码方式。

        在建表的时候可以在最后小括号的")"的右边使用:

                ENGINE来指定存储引擎。

                CHARSET来指定这张表的字符编码方式。

        结论:

                mysql默认的存储引擎是:InnoDB

                mysql默认的字符编码方式是:utf8

(4)怎么查看mysql支持哪些存储引擎呢?

        数据库版本:select version();

        当前版本支持的存储引擎: show engines \G

        mysql支持九大存储引擎,当前mysql 5.5.36支持8个。版本不同支持情况不同。

(5)关于mysql常用的存储引擎介绍一下(了解)

1)MyISAM存储引擎的特点?如何存储数据?

 它管理的表具有以下特征: 

  1.  使用三个文件表示每个表:
    1. 格式文件 — 存储表结构的定义(mytable.frm)
    2. 数据文件 — 存储表行的内容(mytable.MYD)
    3. 索引文件 — 存储表上索引(mytable.MYI):索引是一本书的目录,缩小扫描范围,提高查询效率的一种机制。
  2. 可被转换为压缩、只读表来节省空间

MyISAM存储引擎的优点:

        可被转换为压缩、只读表来节省空间

        这是这种存储引擎的优势!!!!

MyISAM存储引擎的缺点:

        不支持事务机制,安全性低

mysql入门基础-dljd-老杜-编程知识网

2)InnoDB存储引擎的特点?如何存储数据?

这是mysql默认的存储引擎,同时也是一个重量级的存储引擎。

InnoDB支持事务,支持数据库崩溃后自动恢复机制。

InnoDB存储引擎最主要的特点是:非常安全。

它管理的表具有下列主要特征:

        每个 InnoDB 表在数据库目录中以.frm 格式文件表示

        InnoDB 表空间 tablespace 被用于存储表的内容(表空间是一个逻辑名称。表空间存储数据+索引。)

        提供一组用来记录事务性活动的日志文件

        用 COMMIT(提交)、SAVEPOINT 及ROLLBACK(回滚)支持事务处理

        提供全 ACID 兼容

        在 MySQL 服务器崩溃后提供自动恢复

        多版本(MVCC)和行级锁定

        支持外键及引用的完整性,包括级联删除和更新

InnoDB最大的特点就是支持事务:

        以保证数据的安全。效率不是很高,并且也不能压缩,不能转换为只读,不能很好的节省存储空间。

3)MEMORY存储引擎的特点?如何存储数据?

使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,

这两个特点使得 MEMORY 存储引擎非常快。

MEMORY 存储引擎管理的表具有下列特征:

        – 在数据库目录内,每个表均以.frm 格式的文件表示。

        – 表数据及索引被存储在内存中。(目的就是快,查询快!)

        – 表级锁机制。

        – 不能包含 TEXT 或 BLOB 字段。

MEMORY 存储引擎以前被称为HEAP 引擎。

MEMORY引擎优点:查询效率是最高的。不需要和硬盘交互。

MEMORY引擎缺点:不安全,关机之后数据消失。因为数据和索引都是在内存当中。

十四、约束

1、生活需求

        创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性!!!约束的作用就是为了保证:表中的数据有效!!

2、解决方案

  1. 非空约束:not null
  2. 唯一性约束: unique
  3. 主键约束: primary key (简称PK)
    1. 自然主键:主键值是一个自然数,和业务没关系。

    2. 业务主键:主键值和业务紧密关联,例如拿银行卡账号做主键值。这就是业务主键!

    3. 在实际开发中使用业务主键多,还是使用自然主键多一些?

      自然主键使用比较多,因为主键只要做到不重复就行,不需要有意义。

      业务主键不好,因为主键一旦和业务挂钩,那么当业务发生变动的时候,

      可能会影响到主键值,所以业务主键不建议使用。尽量使用自然主键。

  4. 外键约束:foreign key(简称FK):
    1. 为了保证cno字段中的值都是100和101
    2. 思考:子表中的外键引用的父表中的某个字段,被引用的这个字段必须是主键吗?

      不一定是主键,但至少具有unique约束。

    3. 测试:外键可以为NULL吗?

      外键值可以为NULL。

  5. 检查约束:check(mysql不支持,oracle支持)
  1. 列组约束
  2. 表级约束 

3、典型案例

//   1、新需求:name和email两个字段联合起来具有唯一性!!!!

drop table if exists t_vip;

create table t_vip(

        id int,

        name varchar(255),

        email varchar(255),

        unique(name,email) // 约束没有添加在列的后面,这种约束被称为表级约束。

);

//  2、unique 和not null可以联合吗?

drop table if exists t_vip;

create table t_vip(

        id int,

        name varchar(255) not null unique

        在mysql当中,如果一个字段同时被not null和unique约束的话,该字段自动变成主键字段。(注意:oracle中不一样!)

);

//  3、联合(复合)主键

create table t_vip(

        id int,

        name varchar(255),

        email varchar(255),

        primary key(id,name)

        在实际开发中不建议使用:复合主键。建议使用单一主键!

);

十五 数据库三大范式

1 生活问题

        设计表时有什么依据?三大范式。

        设计数据库表的时候,按照三大范式进行设计,可以避免表中数据的冗余,空间的浪费。

2 解决方案

(1)思想

        什么是数据库设计范式?

        数据库表的设计依据。教你怎么进行数据库表的设计。

(2)第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分。

学生编号         学生姓名         联系方式

————————————————————————————

1001                 张三              zs@gmail.com, 1359999999

1002                 李四             ls@gmail.com,13699999999

1001                 王五             ww@163.net,13488888888

以上是学生表,满足第一范式吗?

        不满足。联系方式可以分为邮箱地址和电话

(3)第二范式:建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,不要产生部分依赖。

学生编号+教师编号(pk)        学生姓名        教师姓名

—————————————————————————————-

   1001 001                             张三                 王老师

   1002 002                             李四                 赵老师

   1003 001                             王五                 王老师

   1001 002                              张三                 赵老师

满足第二范式吗?

        不满足,“张三”依赖1001,“王老师”依赖001,显然产生了部分依赖。

产生部分依赖有什么缺点?

        数据冗余了。空间浪费了。“张三”重复了,“王老师”重复了。

背口诀:多对多怎么设计?

        多对多,三张表,关系表两个外键!!!!!!!!!!!!!!!

(4)第三范式:建立在第二范式的基础之上,要求所有非主键字段直接依赖主键,不要产生传递依赖。

学生编号(PK)         学生姓名         班级编号               班级名称

————————————————————————————————–

1001                                 张三                 01                 一年一班

1002                                 李四                 02                 一年二班

1003                                 王五                 03                 一年三班

1004                                 赵六                 03                 一年三班

分析以上表是否满足第三范式?

        不满足。“一年一班” 依赖 “01”(非PK),“01” 依赖 “1001”(PK),产生了传递依赖。

背口诀:

        一对多,两张表,多的表加外键!!!!!!!!!!!!

 (4)总结表的设计?  

  1. 一对多:口诀:一对多,两张表,多的表加外键!!!!!!!!!!!!
  2. 多对多:口诀:多对多,三张表,关系表两个外键!!!!!!!!!!!!!!!
  3. 一对一:口诀:一对一,外键唯一!!!!!!!!!!
           一对一放到一张表中不就行了吗?为啥还要拆分表?
           在实际的开发中,可能存在一张表字段太多,太庞大。这个时候要拆分表。
           一对一怎么设计?没有拆分表之前:一张表。
           拆分表,口诀:一对一,外键唯一!!!!!!!!!!     

(5)嘱咐一句话:以满足客户需求为准

        数据库设计三范式是理论上的。

        实践和理论有的时候有偏差。

        最终的目的都是为了满足客户的需求,有的时候会拿冗余换执行速度。

        因为在sql当中,表和表之间连接次数越多,效率越低。(笛卡尔积)

        有的时候可能会存在冗余,但是为了减少表的连接次数,这样做也是合理的,

        并且对于开发人员来说,sql语句的编写难度也会降低。

        面试的时候把这句话说上:他就不会认为你是初级程序员了!

十五 DBA常用命令?

  1. 重点掌握:数据的导入和导出(数据的备份)
  2. 其它命令了解一下即可。(这个培训日志文档留着,以后忘了,可以打开文档复制粘贴。
  3. 数据导出?
    注意:在windows的dos命令窗口中:mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123456
  4. 可以导出指定的表吗?
    mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot -p123456
  5. 数据导入?
    注意:需要先登录到mysql数据库服务器上。
    然后创建数据库:create database bjpowernode;
    使用数据库:use bjpowernode
    然后初始化数据库:source D:\bjpowernode.sql

十六 特殊需求

1 两个子查询结果相除

  1. https://zhidao.baidu.com/question/226428906.html    
    1. 方式1:select语句中两条子查询结果相除。
    2. 方式2:首先,两个子查询join。其次,select语句中分别得到两个子查询的字段并相除。
  2. https://blog.csdn.net/being_towards_death/article/details/84527260
    1. 方式2。用函数处理结果:CAST、ROUND、COALESCE。
  3. https://easylearn.baidu.com/edu-page/tiangong/questiondetail?id=1711656412511576434&fr=search
    1. 方式1。备注:查询公共表:from dual
  4. https://wenku.baidu.com/view/2706526db007e87101f69e3143323968011cf401.html?_wkts_=1671077015204&bdQuery=select%E8%AF%AD%E5%8F%A5%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F
    1. sql语句的执行顺序 
  5. https://cloud.tencent.com/developer/ask/sof/209391  
    1. 方式1。方式2。条件聚合。
  6. https://huaweicloud.csdn.net/63357061d3efff3090b57041.html
    1. 方式1。as xxxxxx。​​​​​​​
  7. https://www.nuomiphp.com/a/stackoverflow/zh/622ab5d1fb0ae3077501cd5f.html
    1. 方式1。
  8. https://blog.csdn.net/weixin_43865008/article/details/116263675
    1. 方式1。方式2。