黑马程序员技术交流社区

标题: 刚开始学数据库这几天记得笔记 [打印本页]

作者: 243593321    时间: 2019-7-14 14:50
标题: 刚开始学数据库这几天记得笔记
数据库的基本概念英文:DataBase  简称 :DB
定义:用于存储和管理数据的仓库
特点:
·持久化存储数据(到硬盘中),速度快。其实数据库就是一个文件系统
·方便存储和管理数据
·使用了统一的方式操作数据库 -- SQL
MySQL基本使用【卸载】
·控制面板 - 卸载 - 找到MySQL卸载
·找到MySQL安装路径并删除剩余文件
·找到MySQL数据路径C:\ProgramData\MySQL并删除剩余文件
·删除注册表,[cmd] : regedit 打开注册表 MACHINE - SYSTEM - CONTROLSET001 - SERVICES - EVENLOG - APPLICATION - MYSQL
【(了解)启动、关闭服务】(cmd以管理员权限启动)
·[cmd] : services.msc 找到MySQL服务手动启动、关闭
·[cmd] : net start mysql 启动服务
·[cmd] : net stop mysql 关闭服务
【登录】
·[cmd] : mysql -uroot -p密码
·[cmd] : mysql -hip -uroot -p连接目标的密码 (h指host,ip是ip地址,本机ip为127.0.0.1)
·[cmd] : mysql --host=ip --user=root --password=连接目标的密码
【退出】
·[cmd] : exit
·[cmd] : quit
【目录结构】
  1. MySQL安装目录:basedir="E:/develop/MySQL/"
     * 在配置文件 my.ini 中可以查看到
  2. MySQL数据目录:datadir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/"
     * 数据库:文件夹
     * 表:文件夹中的文件
     * 数据:文件中的数据
SQLSQL 全称:Structured Query Language:结构化查询语言
就是定义了操作所有[关系型]数据库的规则。每一种数据库操作的方式存在不一样的地方,称为“方言”。

【SQL 通用语法】
·SQL 语句可以单行或多行书写,以分号 ; 结尾。
·可使用空格和缩进来增强语句的可读性。
·MySQL 数据库的 SQL 语句不区分大小写,关键字建议使用大写。
·[3种注释方式]
  * 单行注释: -- 注释内容 (注意中间有空格,建议使用此方法)
              # 注释内容   (中间可以没有空壳,是mysql 特有)
  * 多行注释: /* 注释内容 */

【SQL 四种分类】##【面试重点】
1) DDL (Data Definition Language)   数据定义语言
    增删改查数据库,表,列(等数据库对象)。           关键字:create(增加), drop(删除),alter(修改),show(查询)等
2) DML (Data Manipulation Language) 数据操作语言
    增删改数据库中的表的数据。                        关键字:insert(增加), delete(删除), update(修改) 等
3) DQL (Data Query Language)        数据查询语言
    查询数据库中的表的数据。                          关键字:select(查询), where(条件查询) 等
4) DCL (Data Control Language)      数据控制语言(了解)
    定义数据库的访问权限和安全级别,创建、删除用户。    关键字:GRANT(授权), REVOKE(撤销权限) 等
DDL操作数据库CRUD【C(Create):创建】
·create database 数据库名称;                         -- 创建数据库 【重点掌握】
·create database if not exists 数据库名称;           -- 创建数据库,判断不存在,再创建(仅了解)
·create database 数据库名称 character set 字符集名;   -- 创建数据库,并指定字符集(仅了解)
   
·[练习]:创建db4数据库,判断是否存在,并制定字符集为gbk。
  create database if not exists db4 character set gbk;

【R(Retrieve):查询】
·show databases;                                     -- 查询所有数据库的名称:
·show create database 数据库名称;                     -- 查询某个数据库的字符集:查询某个数据库的创建语句

【U(Update):修改】
·alter database 数据库名称 character set 字符集名称;   -- 修改数据库的字符集

【D(Delete):删除】(危险,谨慎操作)
·drop database 数据库名称;                            -- 删除数据库
·drop database if exists 数据库名称;                  -- 判断数据库存在,存在再删除

【使用数据库】
·select database();                                  -- 查询当前正在使用的数据库名称
·use 数据库名称;                                      -- 使用数据库
数据库常用数据类型数据类型:

- int 整数类型
  ·使用举例: age int,  

- double 小数类型
  ·使用举例: score double(5,2)   -- 总共有5位,其中小数占2位,整数占5-2=3位;
  ·注意:可以不指定()内的内容

- varchar:字符串类型
  ·使用举例: name varchar(20)   -- 姓名最大20个字符,如 zhangsan 是8个字符,张三 是2个字符
  ·注意:必须指定()内的长度
  ·与char的区别:varchar是可变字符串,更省空间,char是不可变字符串

- date:日期,只包含年月日
  ·格式: yyyy-MM-dd

- datetime:日期,包含年月日时分秒
  ·格式: yyyy-MM-dd HH:mm:ss

- timestamp:时间蹉类型 包含年月日时分秒
  格式: yyyy-MM-dd HH:mm:ss
  ·与datetime的区别:如果将来不给这个字段赋值,或赋值为null,则默认使用当前的系统时间,来自动赋值
DDL操作表【C(Create):创建】【重点】
·[语法]:                        ·[使用举例 - 创建学生表]
create table 表名(                 create table student(
    字段名1 数据类型1 约束,                id int,
    字段名2 数据类型2 约束,                name varchar(32) NOT NULL,
    ... ...                               age int ,
    字段名n 数据类型n 约束                 score double(4,1),
);                                        birthday date,
- 注意:最后一列不需要加逗号 ,              insert_time timestamp
                                   );
·[复制表]:
create table 新建表名 like 被复制的表名;

【R(Retrieve):查询】
·show tables;                                       -- 查询某个数据库中所有的表名称
·desc 表名;                                         -- 查询表结构

【U(Update):修改】
·alter table 表名 rename to 新的表名;                -- 修改表名
·alter table 表名 character set 字符集名称;          -- 修改表的字符集
·alter table 表名 add 列名 数据类型;                 -- 添加一列
·alter table 表名 change 列名 新列名 新数据类型;      -- 修改列名称、类型
·alter table 表名 modify 列名 新数据类型;            -- 修改列类型
·alter table 表名 drop 列名;                         -- 删除列

【D(Delete):删除】
·drop table 表名;               -- 删除一个表
·drop table if exists 表名      -- 判断一个表如果存在就删除
DML增删改表中数据【添加数据】
·[语法]:
  insert into 表名(列名1,列名2,...列名n) values(值1,值2,...值n);

·注意:
- 列名和值的数量和类型必须一致,不赋值的字段给null值
- 如果表名后,不定义列名,则默认给所有列添加值
  简化格式:insert into 表名 values(值1,值2,...值n);
- 批量插入:insert into 表名 values(值1,值2,...值n),(值1,值2,...值n),(值1,值2,...值n)...
- 除了数字类型,其他类型需要使用引号(单双都可以)引起来

【删除数据】
·[语法]:
  delete from 表名 where 条件

·注意:
- 如果不加条件,则删除表中所有记录。
- 如果要删除所有记录
  - delete from 表名; -- 不推荐使用。有多少条记录就会执行多少次删除操作
  - TRUNCATE TABLE 表名; -- 推荐使用。先删除表,然后再创建一张一样的表。只执行删增两次操作,效率更高,

【修改数据】
·[语法]:
  update 表名 set 列名1 = 值1, 列名2 = 值2,... where 条件;

·注意:
- 如果不加任何条件,则会将表中所有记录全部修改。
DQL查询表中数据·select * from 表名;      -- 查询一张表所有的信息

·[语法]:
select               
      字段列表                                       
from
      表名列表
where
      条件列表
group by
      分组字段
having
      分组之后的条件  
order by
      排序
limit
      分页限定
DQL基础查询·查询多字段
  select 字段名1,字段名2... from 表名;
  注意:如果查询所有字段,则可以使用*来替代字段列表。
        字段名可以通过表名.出来

·去除重复(一般只针对一个字段)
  select distinct 字段名 from 表名;

·计算列
  一般针对数字列(int、double)使用四则运算计算值
  ifnull(表达式1,表达式2):如果表达式1为null,就把表达式1替换为表达式2,。null参与的运算,计算结果都为null

·起别名:
  字段名、表名 as 新名称                  -- as可以省略,字段名+空格+新名称(新名称若为汉字,不需要用引号,直接使用)
                                         -- 同一张表在一个查询中可以起多个别名,用于自关联映射
DQL条件查询·[语法]:
  where 条件

- 运算符
  · >   <   <=   >=   =   !=   <>
  · BETWEEN...AND                       -- 例:   BETWEEN 20 AND 30   -- [20,30] 左右都包括,小的数必须放在前面         
  · IN(集合)                            -- 例:   IN(18,20,22)        -- 18 or 20 or 22,即存在宇这个集合中,可以简化多个or语句
  · IS NULL /  IS NOT NULL              -- 判断是否为null,null值不能使用 = 和 != 来判断   
  · and / && [与]      or / || [或]      not / ! [非]
  · LIKE:模糊查询                       -- 配合占位符使用,如查询所有带某个字的姓名
     两种占位符:  · 下划线 _            -- 表示单个任意字符
                  · 百分号 %            -- 表示多个任意字符
——DQL条件查询练习· 查询年龄大于20岁
   SELECT * FROM student WHERE age > 20;
-- 查询年龄大于等于20岁
   SELECT * FROM student WHERE age >= 20;
-- 查询年龄等于20岁
   SELECT * FROM student WHERE age = 20;
-- 查询年龄不等于20岁
   SELECT * FROM student WHERE age != 20;
   SELECT * FROM student WHERE age <> 20;
-- 查询年龄大于等于20并且小于等于30
   SELECT * FROM student WHERE age >= 20 &&  age <=30;
   SELECT * FROM student WHERE age >= 20 AND  age <=30;
   SELECT * FROM student WHERE age BETWEEN 20 AND 30;
-- 查询年龄22岁,18岁,25岁的信息
   SELECT * FROM student WHERE age = 22 OR age = 18 OR age = 25
   SELECT * FROM student WHERE age IN (22,18,25);
-- 查询英语成绩为null
   SELECT * FROM student WHERE english = NULL; -- 这种写法错误!null值不能使用 = 和 != 来判断
   SELECT * FROM student WHERE english IS NULL;
-- 查询英语成绩不为null
   SELECT * FROM student WHERE english  IS NOT NULL;
-- 查询姓马的有哪些? like
   SELECT * FROM student WHERE NAME LIKE '马%';
-- 查询姓名第二个字是化的人
   SELECT * FROM student WHERE NAME LIKE "_化%";
-- 查询姓名是3个字的人
   SELECT * FROM student WHERE NAME LIKE '___';
-- 查询姓名中包含德的人
   SELECT * FROM student WHERE NAME LIKE '%德%';
DQL排序查询·[语法]:
  order by 排序字段1 排序方式1,排序字段2 排序方式2...

·排序方式:
  - ASC:升序,默认的。
  - DESC:降序。

·注意:
  如果有多个排序条件,则当前边的条件值一样时,才会判断第二条件
DQL聚合函数·[语法]:
  SELECT 函数名(字段名) FROM 表名;

聚合函数:将一列数据作为一个整体,进行纵向的计算

·count:计算个数
  一般选择非空的列:主键(如学号,编号等)
  count(*)   *表示,一行数据中只要有一个不为null,那么这行就算一条数据,一般不使用此方法
·max:计算最大值
·min:计算最小值
·sum:计算和
·avg:计算平均值

·注意:聚合函数的计算,要排除null值。
  解决方案:
          - 选择不包含空的列进行计算
          - 使用IFNULL函数
DQL分组查询·[语法]:
  SELECT 分组字段,聚合函数1,聚合函数2... FROM 表名 WHERE 分组前的条件 GROUP BY 分组字段 HAVING 分组后的条件;

·注意:
  - 分组之后查询的字段:分组字段、聚合函数,聚合函数可以起别名使用
  - where 和 having 的区别? 【面试重点】
    - where 在分组之前进行限定,如果不满足条件,则不参与分组。having在分组之后进行限定,如果不满足结果,则不会被查询出来
    - where 后不可以跟聚合函数,having可以进行聚合函数的判断。

·练习:
  -- 按照性别分组。分别查询男、女同学的平均分
     SELECT sex , AVG(math) FROM student GROUP BY sex;

  -- 按照性别分组。分别查询男、女同学的平均分,人数
     SELECT sex , AVG(math),COUNT(id) FROM student GROUP BY sex;
  
  -- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人,不参与分组
     SELECT sex , AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex;
  
  -- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人,不参与分组,分组之后。人数要大于2个人
     SELECT sex , AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex HAVING COUNT(id) > 2;
     SELECT sex , AVG(math),COUNT(id) 人数 FROM student WHERE math > 70 GROUP BY sex HAVING 人数 > 2;
DQL分页查询·[语法]:
  limit 开始的索引,每页查询的条数;

  注意:开始的索引可以省略,省略不写则默认为0

·公式:开始的索引 = (当前的页码 - 1) * 每页显示的条数

  举例:每页显示3条记录

  SELECT * FROM student LIMIT 0,3; -- 第1页
  
  SELECT * FROM student LIMIT 3,3; -- 第2页
  
  SELECT * FROM student LIMIT 6,3; -- 第3页

·limit 是一个MySQL"方言"
DCL—管理用户(了解)DCL:管理用户,授权,在公司中由DBA(数据库管理员)来管理;  本机主机名:localhost;
·添加用户:
  - 语法:CREATE USER '用户名账号'@'主机名/电脑IP地址' IDENTIFIED BY '密码';
·删除用户:
  - 语法:DROP USER '用户名'@'主机名';
·修改用户密码:
  - UPDATE USER SET PASSWORD = PASSWORD('新密码') WHERE USER = '用户名';
    - 例: UPDATE USER SET PASSWORD = PASSWORD('abc') WHERE USER = 'lisi';

  - SET PASSWORD FOR '用户名'@'主机名' = PASSWORD('新密码');
    - 例: SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123');

  - mysql中忘记了root用户的密码?
    1. cmd -- > net stop mysql 停止mysql服务 (* 需要管理员运行该cmd)
    2. 使用无验证方式启动mysql服务: mysqld --skip-grant-tables
    3. 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登录成功
    4. use mysql;
    5. update user set password = password('你的新密码') where user = 'root';
    6. 关闭两个窗口
    7. 打开任务管理器,手动结束mysqld.exe 的进程
    8. 启动mysql服务
    9. 使用新密码登录。
·查询用户:
  - 1. 切换到mysql数据库
    USE myql;
  - 2. 查询user表
    SELECT * FROM USER;
DCL—权限管理(了解)通配符: % 表示可以在任意主机使用用户登录数据库

1. 查询权限:
   -- 查询权限
   SHOW GRANTS FOR '用户名'@'主机名/IP地址';
   SHOW GRANTS FOR 'lisi'@'%';

2. 授予权限:
   -- 授予权限
   grant 权限列表 on 数据库名.表名 to '用户名'@'主机名/IP地址';
   -- 给张三用户授予所有权限,在任意数据库任意表上
   
   GRANT ALL ON *.* TO 'zhangsan'@'localhost';

3. 撤销权限:
   -- 撤销权限:
   revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名/IP地址';
   REVOKE UPDATE ON db3.`account` FROM 'lisi'@'%';
约束·概念: 对表中的数据进行限定,保证数据的正确性、有效性和完整性。
·分类:
  ·主键约束:primary key
  ·非空约束:not null
  ·唯一约束:unique
  ·外键约束:foreign key
约束——非空约束·非空约束:not null,某一列的值不能为null

·创建表时添加约束
  CREATE TABLE stu(
         id INT,
         NAME VARCHAR(20) NOT NULL      -- name为非空
  );

·创建表完后,添加非空约束
  ALTER TABLE stu MODIFY NAME VARCHAR(20) NOT NULL;

·删除name的非空约束
  ALTER TABLE stu MODIFY NAME VARCHAR(20);
约束——唯一约束·唯一约束:unique,某一列的值不能重复,对null值不会唯一约束,即可以有多个null值,又叫索引唯一约束

·注意:
  唯一约束可以有NULL值,但是只能有一条记录为null

·在创建表时,添加唯一约束
  CREATE TABLE stu(
         id INT,
         phone_number VARCHAR(20) UNIQUE       -- 手机号唯一
  );

·在表创建完后,添加唯一约束
  ALTER TABLE stu MODIFY phone_number VARCHAR(20) UNIQUE;

·删除唯一约束
  ALTER TABLE stu DROP INDEX phone_number;
约束——主键约束·主键约束:primary key。

·注意:
  - 含义:非空且唯一         - 一张表只能有一个主键         - 主键可以一个或多个字段(联合主键)
  - 主键可以用整数类型:一般和auto_increment结合,缺点:有可能超过整数范围(21亿+)
  - 主键可以用字符串类型:随机生成一个永远不会重复的字符串

·在创建表时,添加主键约束
   create table stu(
          id int primary key,     -- 给id添加主键约束
          name varchar(20)
   );

·创建完表后,添加主键
  ALTER TABLE stu MODIFY id INT PRIMARY KEY;

·删除主键
  ALTER TABLE stu DROP PRIMARY KEY;

·自动增长:
  - 概念:如果某一列是数值类型的,使用 auto_increment 可以来完成值得自动增长
  - 在创建表时,添加主键约束,并且完成主键自增长
    create table stu(
           id int primary key auto_increment,-- 给id添加主键约束
           name varchar(20)
    );
  - 添加自动增长
  ALTER TABLE stu MODIFY id INT AUTO_INCREMENT;
  - 删除自动增长
  ALTER TABLE stu MODIFY id INT;
约束——外键约束·外键约束:foreign key,让表于表产生关系,从而保证数据的正确性。

·在创建表时,可以添加外键
  语法:
       create table 表名(
              ....
             外键列
             constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称)
       );

·创建表之后,添加外键
  ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键列名称) REFERENCES 主表名称(主表列名称);

·删除外键
  ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;

·constraint 外键名称  这个添加外键名称的操作可以省略,此时系统会自动生成一个随机的名字,如果需要做删除等操作使用到名字
  可以查看:show

·级联操作(了解即可)
  - 添加/删除级联操作
    - 语法:ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称)
            ON UPDATE CASCADE / ON DELETE CASCADE;
  - 分类:
    - 级联更新:ON UPDATE CASCADE
    - 级联删除:ON DELETE CASCADE
数据库设计
多表之间的关系·分类:
  · 一对一(了解即可,开发中很少遇到,万一有需求,一般就合成一张表):
     如:人和身份证
     分析:一个人只有一个身份证,一个身份证只能对应一个人
     实现方式:一对一关系实现,可以在任意一方添加唯一外键指向另一方的主键。

  · 一对多(多对一):
     如:部门和员工
     分析:一个部门有多个员工,一个员工只能对应一个部门
     实现方式:在“多”的一方建立外键,指向“一”的一方的主键。

  · 多对多:
     如:学生和课程
     分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择
     实现方式:多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键,这两个主键组合起来作为中间表的联合主键
范式(重复内容拆分)·概念:设计数据库时,需要遵循的一些规范。要遵循后边的范式要求,必须先遵循前边的所有范式要求
  设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。
  目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

·分类:
  1. 第一范式(1NF):每一列都是不可分割的原子数据项(列表头不能合并拆分,一列数据只有一个表头)

     第一范式存在的问题:
     1.存在非常严重的数据冗余(重复):如姓名、系名、系主任
     2.数据添加存在问题:如添加新开设的系和系主任时,没有学生学号等信息,数据不合法
     3.数据删除存在问题:如张无忌同学毕业了,删除数据,会将系的数据一起删除。

  2. 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖)

     ·相关概念:
       1. 函数依赖:A-->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值。则称B依赖于A
          例如: 学号 --> 姓名。   
       2. 完全函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值。
          例如:(学号,课程名称) --> 分数
       3. 部分函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值即可。
          例如:(学号,课程名称) --> 姓名
       4. 传递函数依赖:A-->B, B -- >C . 如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称 C 传递函数依赖于A
          例如: 学号-->系名,系名-->系主任
       5. 码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码
          例如:该表中码为:(学号,课程名称)
          - 主属性:码属性组中的所有属性
          - 非主属性:码属性组之外的属性

     第二范式存在的问题:
     2.数据添加存在问题:如添加新开设的系和系主任时,没有学生学号等信息,数据不合法
     3.数据删除存在问题:如张无忌同学毕业了,删除数据,会将系的数据一起删除。

  3. 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
数据库的备份和还原·cmd命令行:
  ·[语法]:
    - 备份: mysqldump -u用户名 -p密码 数据库名称 > 保存的路径
    - 还原:
      1. 登录数据库 mysqldump -u用户名 -p密码
      2. 创建数据库
      3. 使用数据库
      4. 执行文件。source 文件路径
·图形化工具:
  右键 - 备份/导出 - 备份数据库 - 选择路径并导出
  右键 - 执行SQL脚本 - 选择备份文件导入
多表查询概述:
select * from 表1,表2;
会出现表1、2组合的所有结果(笛卡尔积)
多表查询需要消除其中的无用数据
多表查询—内连接查询·内连接查询:

  ·隐式内连接:配合where(将来用这个)
    - 使用举例:select * from 表A,表B where 表A.主键名 = 表B.主键名
  
  ·显式内连接:(了解,将来不用这个)
    - 语法: select 字段列表 from 表名1 [inner] join 表名2 on 条件      -- inner []表示可省略

·内连接查询的思路:
  - 从哪些表中查询数据
  - 条件是什么
  - 查询哪些字段
多表查询—外连接查询·外链接查询:

  ·左外连接:(将来用这个)
    - 语法:select 字段列表 from 表1 left [outer] join 表2 on 条件;
    - 查询的是左表所有数据以及其交集部分。
    - 注意:left join 左右两侧各只能有一张表
    - 例子:
      - 查询所有员工信息,如果员工有部门,则查询部门名称,没有部门,则不显示部门名称
        SELECT  t1.*,t2.`name` FROM emp t1 LEFT JOIN dept t2 ON t1.`dept_id` = t2.`id`;

  ·右外连接:(了解,将来不用这个)
    - 语法:select 字段列表 from 表1 right [outer] join 表2 on 条件;
    - 查询的是右表所有数据以及其交集部分。
    - 例子:
      SELECT  * FROM dept t2 RIGHT JOIN emp t1 ON t1.`dept_id` = t2.`id`;
多表查询—子查询·子查询的结果是单行单列的:
  - 子查询可以作为条件,使用运算符去判断。 运算符: >  >=  <  <=  =  !=  <>
  - 例子: 查询员工工资小于平均工资的人
    SELECT * FROM emp WHERE emp.salary < (SELECT AVG(salary) FROM emp);

·子查询的结果是多行单列的:
  - 查询可以作为条件,使用运算符in来判断
  - 例子: 查询'财务部'和'市场部'所有的员工信息
    SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部');

    -- 建议使用普通内连接
    SELECT * FROM emp,dept WHERE emp.`dept_id` = dept.`id` and dept.`name` =  '财务部' OR NAME = '市场部';

·子查询的结果是多行多列的:
    * 子查询可以作为一张虚拟表参与查询
  -例子: 查询员工入职日期是2011-11-11日之后的员工信息和部门信息
    -- 子查询
    SELECT * FROM dept t1 ,(SELECT * FROM emp WHERE emp.`join_date` > '2011-11-11') t2 WHERE t1.id = t2.dept_id;
   
    -- 建议使用普通内连接
    SELECT * FROM emp t1,dept t2 WHERE t1.`dept_id` = t2.`id` AND t1.`join_date` >  '2011-11-11'
事务基本介绍:
·概念:
  如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
  
·操作(手动提交):
  - 开启事务: start transaction;    -- 保证一些操作成功
  - 回滚:     rollback;             -- 在java中,如果发生异常,在catch语句中来回滚
  - 提交:     commit;               -- 没有发生问题时,再提交

·MySQL默认自动提交:
  一条DML(数据增删改)语句会自动提交一次事务
  (Oracle 数据库默认是手动提交事务)

·查看事务的默认提交方式:SELECT @@autocommit; -- 结果为 1 代表自动提交  0 代表手动提交
·(了解)修改默认提交方式: set @@autocommit = 0;     -- 把默认自动提交修改为默认手动提交
事务的四大特征(面试)1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
3. 隔离性:多个事务之间。相互独立。
4. 一致性:事务操作前后,数据总量不变
事务的隔离级别(了解)·概念:多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。

·存在问题:
  - 脏读:一个事务,读取到另一个事务中没有提交的数据
  - 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
  - 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。

·隔离级别:
  - read uncommitted:读未提交               - 产生的问题:脏读、不可重复读、幻读,脏读问题很大不建议使用
  - read committed:读已提交 (Oracle默认)  - 产生的问题:不可重复读、幻读,可以使用此方法
  - repeatable read:可重复读 (MySQL默认)  - 产生的问题:幻读,可以使用此方法
  - serializable:串行化                     - 可以解决所有的问题,但是效率低下,不建议使用

  - 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
  - 数据库查询隔离级别: select @@tx_isolation;
  - 数据库设置隔离级别: set global transaction isolation level  级别字符串;

* 演示:
  set global transaction isolation level read uncommitted;
  start transaction;
  -- 转账操作
  update account set balance = balance - 500 where id = 1;
  update account set balance = balance + 500 where id = 2;
JDBC概念Java DataBase Connectivity  Java数据库连接 / Java语言操作数据库
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
JDBC作用:平复数据库数据的差异
快速入门//1.导入驱动jar包
     复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
     libs右键-->Add As Library
//2.注册驱动                                                                   //告诉程序该使用哪一个数据库驱动jar
     Class.forName("com.mysql.jdbc.Driver");
//3.通过 【 DriverManager 驱动管理对象 】 获取 【 Connection 数据库连接对象 】   //搭桥,获取数据库连接
     Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
//4.获取 【 Statement 执行sql的对象 】
     Statement stmt = conn.createStatement();
//5.执行sql
     int count = stmt.executeUpdate(sql语句);
//6.处理结果
     System.out.println(count);
//7.释放资源
     stmt.close();
     conn.close();
DriverManager驱动管理对象 【功能】 1. 注册驱动  2. 获取数据库连接

1. 注册驱动:告诉程序该使用哪一个数据库驱动jar

   方法:static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
   【掌握】代码实现:  Class.forName("com.mysql.jdbc.Driver");   

   通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
      static {
                try {
                     java.sql.DriverManager.registerDriver(new Driver());
                } catch (SQLException E) {  
                     throw new RuntimeException("Can't register driver!");
                }
      }

    注意:mysql5之后的驱动jar包可以省略注册驱动的步骤,但是依然建议手写注册,方便兼容低版本的MySQL。

2. 获取数据库连接:

   【掌握】方法:static Connection getConnection(String url, String user, String password)
   参数:url:指定连接的路径    user:用户名    password:密码
        url语法: jdbc:mysql://ip地址(域名):端口号/数据库名称
        url例子: jdbc:mysql://localhost:3306/db3
        url细节: 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
Connection数据库连接对象 【功能】 1. 获取执行 sql 的对象  2. 管理事务

1. 获取执行 sql 的对象
   方法:
   - Statement createStatement()
   【掌握】 - PreparedStatement prepareStatement(String sql)  

2. 管理事务
   方法:
   - 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,把自动提交关闭(只针对这一次),即开启事务
   - 回滚事务:rollback()
   - 提交事务:commit()
Statement(了解)执行sql的对象 【功能】:执行sql

·SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题,所以以后不使用这个,而使用PreparedStatement
  - 输入用户随便,输入密码:a' or 'a' = 'a
  - sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'

方法:

· 【掌握】 int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句(DDL不常用,了解)
   - 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。

· 【掌握】 ResultSet executeQuery(String sql)  :执行DQL(select)语句      
   - 返回值:ResultSet 这个对象封装了所有结果 (详情见表格下一行)

· boolean execute(String sql) :可以执行任意的sql,返回true表示执行的是DQL查询,返回false表示执行的是DML增删改 (了解)
                                 由于返回的是布尔值,对于我们查询需要得到的结果没有意义,所以不使用
ResultSet结果集对象 【功能】:封装查询结果

·【掌握】方法:
  ·boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
  ·getXxx(参数):获取数据
    - Xxx:代表数据类型   如: int getInt() , String getString()
    - 参数:
           1. int:代表列的编号,从1开始   如: getString(1),获取第1列 id列的值
    (建议)2. String:代表列名称。 如: getDouble("balance") 获取列名是balance的列的值
  
·使用步骤:
    1. 游标向下移动一行
    2. 判断是否有数据
    3. 获取数据

  //循环判断游标是否是最后一行末尾,若不是,获取并打印所有信息。
    【掌握】
    while(rs.next()){
          int id = rs.getInt("id");
          String name = rs.getString("name");
          double balance = rs.getDouble("balance");
          System.out.println(id + "," + name + "," + balance);
    }
PreparedStatement执行sql的对象 【功能】:执行sql

【方法】
·执行DML  int excuteUpdate();//这里不能传入sql语句了
·执行DQL  ResultSet excuteQuery();//这里不能传入sql语句了

·SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
  - 输入用户随便,输入密码:a' or 'a' = 'a
  - sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'

·解决sql注入问题:使用PreparedStatement对象来解决
·预编译的SQL:参数使用?作为占位符
·步骤:
   1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
   2. 注册驱动
   3. 获取数据库连接对象 Connection
   4. 定义sql
      注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
   5. 获取执行sql语句的对象 PreparedStatement  通过方法:connection.prepareStatement(String sql)
   6. 给?赋值:
      方法: setXxx(参数1,参数2)            如:preparedStatement.setString(1,username);
          参数1:?的位置编号 从1 开始          preparedStatement.setString(2,password);
          参数2:?的值
   7. 执行sql,接受返回结果,无参数不能传递sql语句 如:rs = preparedStatement.executeQuery();
   8. 处理结果,如:return rs.next();                    
   9. 释放资源

·注意:后期都会使用PreparedStatement来完成增删改查的所有操作      - 可以防止SQL注入     - 效率更高
JDBCUtils抽取JDBC工具类  目的:简化书写
--注册驱动,获取连接  --释放资源

import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driverClass;
    static{
        try {
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            String path = classLoader.getResource("mysql.properties").getPath();
            Properties prop = new Properties();
            prop.load(new FileReader(path));
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");
            driverClass = prop.getProperty("driverClass");
            Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }  catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    //释放资源
    public static void close(){}
    public static void close(Statement stmt, Connection conn){
        close(null,stmt,conn);
    }
    public static void close(ResultSet rs, Statement stmt, Connection conn){
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
JDBC控制事务·事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

·使用Connection对象来管理事务
  - 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
    * 在执行sql之前开启事务
      conn.setAutoCommit(false);
  - 提交事务:commit()
    * 当所有sql都执行完提交事务
      conn.commit();
  - 回滚事务:rollback()
    * 在catch中回滚事务
      try {
          if(conn != null) {
             conn.rollback();
          }
      } catch (SQLException e1) {
          e1.printStackTrace();
      }






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2