黑马程序员技术交流社区

标题: 数据库 [打印本页]

作者: liweihao5253    时间: 2019-8-14 16:29
标题: 数据库
数据库(DateBase)数据库的基本概念:    数据库是长期存储在计算机内,有组织、大量的、可共享的数据集合。数据库的三个特点
        * 持久化  (数据库就是一个文件系统)
        * 方便储存和管理
        * 提供统一的操作方式

数据库管理系统(Database Management System):简称DBMS市面上常见的几种DBMS:
        * Oracle
        * MySql
        * Sql Server


        * DB2 IBM的数据库,银行系统常用
        * SQLite嵌入式小型数据库,手机端和浏览器常用
        * MySql阿里巴巴版,满足大并发需求
        * MariaDB——MySql原作者的另一个产品,底层和MySql一样


以上都是关系型数据库 Relational

启停MySql服务的cmd命令:

services.msc  //打开windows服务窗口
net start mysql  //启动mysql服务
net stop mysql  //停止mysql服务
netstat -aon  //显示端口列表
cmd窗口显示中文乱码问题
切换为UTF-8:chcp 65001
切换回GBK:chcp 936

CMD登录数据库的操作步骤

mysql -uroot -proot [-P](-P用来设置端口号,默认连接3306端口)
注:如果-p之后不写密码,会提示输入密文密码,这样更安全
mysql -h127.0.0.1 -uroot -proot -P3306
第二种方式:写全称
mysql --host=ip --user=root --password=root
退出数据库的命令:
quit  退出数据库
exit; 关闭cmd

MySql软件安装目录
my.ini ——mysql的配置文件
mysql的数据目录结构
    数据库——文件夹
    表——文件
    数据——文件中的数据

SQL语句 (Structured Query Language)
定义了操作所有关系型数据库的规则。
每一种数据库的操作方式存在不一样的地方,称为方言。
语法:
    以多行或单行的形式书写,分号结尾
    可以用空格或缩进
    大小写不敏感,建议大写
    三种注释
        单行注释  -- 中划线右面要有空格  例如:show databases;  -- 查询所有数据库
                        #(可以不加空格)
        多行注释 /* */
SQL从功能上分为四类
①DDL(数据定义语句):数据库和表的定义、索引的定义
②DML(数据操纵语句):数据库和表的增删改
③DQL(数据查询语句):表数据的查询
④DCL(数据控制语句):数据库的安全性控制、管理用户

DDL(数据定义语句)
    ——操作数据库和表
CRUD:分别对用四种操作
操作数据库
Create 创建数据库
    create database db1;
    create database if not exists db1; -- 先判断再创建
    create database db2 character set gbk; -- 创建时指定字符集
    create database if not exists db3 character set gbk; -- 综合使用
Rtrieve 显示数据库
    show databases;show tables;
    show create database mysql; -- 查看某个数据库的创建语句(包含字符集信息)
Update 更改数据库
    alter database db1 character set utf8; -- 注意不加中划线
Delete 删除数据库
    drop database db1;
    drop database if exists db1; -- 先判断再删除

使用数据库
查询当前正在使用的数据库名称
    select database();
    use db1;

操作表
Create 创建表
    create table table1(
        列名1 数据类型1,
        列名2 数据类型2,
        ...
        列名3 数据类型3);
    数据类型
        整数 int
        小数 double(5,2)  -- 最多5位,小数点后保留2位
        日期 date -- 只包含年月日,格式为 yyyy-MM-dd
                datatime -- 包含年月日时分秒,格式为 yyyy-MM-dd HH:ss:mm
                timestamp -- 特点:如果不赋值,则默认使用添加记录时系统时间自动赋值
        字符串 varchar(20) -- 最大20个字符
    create table stu like student; -- 克隆student表
Rtrieve 显示表
    show tables;    -- 查询某个数据库中所有表名称
    desc table1; -- 查询某个表结构  description
Delete 删除表
    drop table t1;
    drop table if exists t1;
Update 修改表
    alter table t1 rename to t2; -- 修改表名
    show create table t2;
    alter table t1 character set gbk; -- 修改表的字符集
    修改列
    alter table t1 add gender varchar(10); -- 添加一列
    alter table t1 change gender sex varchar(10); -- 修改列名
    alter table t1 modify sex varchar(20); -- 篡改列的类型
    alter table t1 drop sex; -- 删除列

DML(数据操作语句)
        ——增删改表中数据
     添加数据
     insert into student(id,name,gender) values(1,'张无忌','男');
     注意事项:列名和值要一一对应,值类型也要对应
                      如果不写列名,默认给所有字段添加值
                      不想赋值的列,可以用NULL代替
                      除了数字类型,其他类型需要使用引号(单双都行)
    日期使用 '1994-04-05'的格式赋值
    更新数据
    update student set age=19,set score=90 where id=1; -- 多个记录用逗号隔开
    删除数据
    delete from student; -- 删除所有数据,效率低,一条一条地删除,但是有日志记录,有可能找回来
    delete from student where id=1; -- 删除表中id为1的数据
    truncate table student; -- 删除表,然后再创建一个一模一样的空表,效率更高,推荐使用,不过这种删除的更彻底,找不回来
DQL(数据查询语句)
        ——查询表中数据
    例如:select * from student;
    语法格式:
    select 字段列表
        from 表明列表
            where 条件列表
                group by 分组字段
                    having 分组之后的条件
                        order by排序
                            limit 分页限定
    多个字段查询 用逗号隔开
        select name,age,score from 表名;
    去重
        select distinct address from student;
    计算
        select name ,math,english,math+english from student;
        如果算式中包含null,则结果也为null
        select name ,math,ifnull(english,0) ,math+english from student;
        如果english为null,则替换成0
        注意 IFNULL 方法不用来修饰原始列,而是用来修饰结果列
    起别名
         select name ,math,ifnull(english,0) ,math+english [as] 总分 from student;
         select name ,math,ifnull(english,0) ,math+english 总分 from student;
    逻辑运算符
        >  <  =  <> !=  >=  <=  
        between ... and ...
        AND  &&
        OR  ||
        IN关键字
            例如:where math IN (88,90,99) -- math在其中
    模糊查询   
        使用LIKE关键字
                % 任意个任意字符
                _  单个任意字符
    判断空值
            IS NULL
            IS NOT NULL

第二天
1、DQL
排序
    order by 排序字段 [排序方式] [,排序字段 排序方式]
    排序方式
        ASC 升序(默认)
        DESC 降序
聚合函数
    将一列数据作为一个整体,进行纵向运算
        count -- 计算个数
        max -- 计算最大值
        min -- 计算最小值
        sum -- 求和
        avg -- 计算平均值
    案例
        select sum(name) from student3;
    注意,聚合函数的运算会忽略NULL值
    解决方式
        ①避免计算包含null的列(选择主键计算)
        ②select count(ifnull(english,0)) from student3;
        ③select count(*) from student3; -- 只要有数据就会计算

分组计算查询(和聚合函数搭配使用)
    group by 分组字段
    注意,1 分组之后查询的字段:分组字段或聚合函数,其他字段没意义
    select  sex,avg(math) from student3 group by sex;-- 按照性别分组,分别求男、女平均分
    select  sex,avg(math), count(id) from student3 group by sex;-- 按照性别分组,分别求男、女平均分
    分组计算前的条件限定
    select  sex,avg(math) from student3 where math>70 group by sex; --不满足条件不参与分组
    having 关键字
    分组计算后的条件限定
    select  sex,avg(math) from student3 group by sex having count(id)>2;
    关键字having是以组为最小单位做判断,判断的内容必须和组有关系
注意where和having的区别:
    where在分组前对单条数据筛选,后面不可以跟聚合函数
    having在分组后对组筛选,后面可以跟聚合函数

分页查询
    limit 起始索引, 条目数量
    公式:起始索引 = (当前页码-1)* 每页条目数量
    select * from student3 limit 2,6;
    -- 查询学生表中数据,从第 3 条开始显示,显示 6 条
    注意,分页操作的limit语法是方言,不同的数据库系统有不同的分页语法

2、约束
    ——对表中数据进行限定,保证数据的正确性、有效性、完整性
    1、主键约束 primary key  ——非空且唯一
            ①一张表只能有一个主键
            ②主键是表中记录唯一表示
            关键字 primary key
        添加:
            ①创建表的时候在字段定义的后面声明primary key
            ②修改表的时候 ALTER TABLE 表名 ADD PRIMARY KEY(字段名);
        删除:
            使用 alter table student drop primary key
            不需要写列名,因为一个表只有一个主键
            添加约束时,不能有重复元素和null值

        自动增长
            如果某一列是数值类型,使用auto_increment关键字完成自动增长
            语法: primary key auto_increment
            删除时,使用alter修改表,字段部分直接不写
            注意,只能有一个字段被设置成自增
    2、非空约束 not null
            ①创建表时添加约束
                关键字 not null
            ②创建后修改表的字段时添加约束
            删除约束时,直接不写约束就行
            
    3、唯一约束 unique
            关键字 unique
            注意,添加约束时,不能有重复元素
                    mysql中唯一约束的值可以有多条null
            注意,删除的时候需要特别语句 drop index 字段名
            例如:alter table student drop index phone;

    4、外键约束 foreign key
            ——在一张表中记录另一张表的主键信息,减少冗余
            [constrant 外键名] foreign key (外键列名) references 主表 (列名)
            注意,上述外键名只是索引名,要先添加外键列再添加外键约束
            数据冗余 拆分表
            删除外键约束
            alter table employee drop foreign key 外键名
            创建后再添加外键约束
            alter table employee add constrant 外键名 foreign key (外键列名) references 主表 (列名)
            注意,外键列不一定是主键,只要是唯一属性的都可以作为外键
                        外键可重复也可以为null,但不能是主表不存在的值
            学习如何用工具操作
            级联操作
                级联更新
                    需要在添加外键的同时,设置级联
                    on update cascade
                级联删除 (危险操作!慎用!)
                    on delete cascade
            
3、多表关系
    1、一对一
        人 - 身份证
        如何实现?
        任意一方设置外键关联对方的主键,并且让其外键唯一
    2、一对多(多对一)重要
        部门 - 员工
    3、多对多
        学生 - 课程(至少出现三张表) 需要设计学生-课程关系表
        关系表建议设置联合主键
4、范式
        ——设计数据库时需要遵循的规范
    第次规范
    第一范式、第二范式、第三范式
    冗余度随级别升高而减少
    第一范式(1NF):每一列都是不可分割的原子数据项
     第二范式 (2NF):在1F的基础上,消除非主属性对码的部分依赖(不完全依赖)
        函数依赖 A -> B 如果通过A能确定B,则成B依赖于A
        学号 -> 姓名 姓名依赖于学号
        属性组(学号,课程) -> 分数
        完全函数依赖 A -> B 如果A是一个属性组,则B的属性值确定完全依赖与A属性组
        不完全依赖 A -> B 如果A是一个属性组,则B的属性值确定只依赖于A的部分属性
        传递函数依赖 A -> B  && B-> C  => A -> C  称:C传递依赖于A
            学号 -> 系别 系别 -> 系主任
        码: 在一张表中,一个属性或属性组被其他所有属性所依赖
            属性组(学号+课程名称)为一个码
    第三范式 (3NF):消除传递依赖
5、数据库备份还原
        数据库管理员的工作
    1、命令行
            备份:
            mysqldump -u用户名 -p密码 数据库名称> 保存的路径(以sql的形式保存)     还原:
            注意,还原之前要保证MySql中存在一个空的同名数据库
            use 数据库名称; source sql路径名;
    2、图形化工具
            点点鼠标

第三天
1、多表查询
笛卡尔积:有两个集合A ,B ,取这两个集合的所有组合情况
笛卡尔积就是多表连接查询
select * from emp,dept
因此要消除笛卡尔积中无用的数据
多表查询的分类
1、内连接查询
    1、隐式内连接
        使用where语句
        select * from emp,dept where emp.dept_id=dept.id
        给字段起别名
        select...
            from emp t1,emp t2 -- 起别名
                where...
        (sql语句建议竖着写,方便加注释)
    2、显式内连接
        语法:select 字段 from 表名1 [inner] join 表名2 on 条件
        select * from emp inner join dept on emp.dept_id=dept.id;
        select * from emp inner dept on emp.dept_id=dept.id;
2、外连接查询
        1、左外连接
            语法:select 字段列表 from 表名1 left [outer] join 表名2 on 条件
            select * from emp left outer join dept on emp.dept_id=dept.id;
            select * from emp left join dept on emp.dept_id=dept.id;
            以左表为主,查询左表所有信息,根据连接条件显示出对应的右表的信息
        2、右外连接
            语法:select 字段列表 from 表名1 right [outer] join 表名2 on 条件
            select * from emp right outer join dept on emp.dept_id=dept.id;
            select * from emp right join dept on emp.dept_id=dept.id;
            以右表为主,查询右表所有信息,根据连接条件显示出对应的左表的信息
        注意:左外连接和右外连接可以相互转换,只是一个相对的概念,一般使用左外连接即可
3、子查询
        ——查询中嵌套查询,称为子查询
        前两种查询都是将上一个查询语句的结果作为下一个查询的条件
        子查询是虚拟表作为查询的目标
    1、子查询的结果是单行单列
        子查询结果作为条件,使用逻辑运算符 = > < 去判断
            -- 查询工资小于平均工资的人
            select * from emp where salary < (select AVG(salary) from emp)
    2、子查询的结果是多行单列
        子查询结果作为条件,由于条件是一个集合,使用逻辑运算符 IN 去判断
            -- 查询财务部和销售部所有员工的信息
            select * from emp where dept_id in (select id from dept where name='财务部' or name='销售部' )
    3、子查询的结果是多行多列
        上一个结果作为一个虚拟表作为表的查询,而不是条件
            -- 查询入职日期是2011-11-11日之后的员工信息和部门信息
            select * from dept t1, (select * from emp where emp.join_date > '2011-11-11') t2 where t1.id = t2.dept_id;
    嵌套查询的优缺点
    优点:嵌套查询是先筛选再连接,处理的数据量更小,效率更高
    缺点:查询的字段只能是父表中的字段,无法获取子查询中的字段,而连接查询                 可以查询到多表的任何字段
   
       concat(字段1,字段2)语法可以拼接两个字段
2、事务(transaction)
    1、事务的基本介绍
        如果一个业务包含多个步骤,被事务管理,要么都做、要么都不做
    2、操作
        开启 start transaction;
        提交 commit;
            1、分为默认提交和手动提交
                在mysql数据库中一条DML语句会默认自动提交事务
                一旦start transaction就必须手动提交,否则数据不会持久化更改
            2、修改事务的提交方式
                查看提交方式:select @@autocommit
                    1代表自动提交
                    0代表手动提交
                设置提交方式:set @@autocommit=1
        回滚 rollback;
    3、事务的四个特征(ACID)
        ①原子性(Atomicity):不可分割的最小操作单位,要么都做要么都不做
        ②一致性(Consistency):事务操作前后数据总量不变
        ③隔离性(Isolation):多个事务之间相互独立
        ④持久性(Durability):事务一旦提交或回滚后,数据库会持久化保存数据
    4、事务的隔离级别
        问题
        1、脏读:一个事务读到了另一个事务没有提交的数据
        2、不可重复读:同一个事务中两次读到的数据不一样
        3、幻读:
        隔离级别
            1、读未提交 未解决问题:1,2,3
            2、读已提交 未解决问题:2,3 (Oracle默认)
            3、可重复读 未解决问题:3 (MySql默认)
            4、串行化 解决所有问题
        隔离级别越高安全性越高,效率越低,二者去平衡
        如何设置数据库隔离级别?参考学校笔记
        
3、DCL (数据库控制语言)
管理数据库用户

第四天
1、JDBC基本概念
    什么是JDBC?
官方定义了一系列操作关系型数据库的规则,即接口,各个数据库厂商实现了这个接口,提供驱动程序jar包,我们可以使用这套接口进行编程,真正执行的是jar包里的实现类
2、使用
    1、导入jar包
        两种方式:直接引用外部jar包
                        先复制到项目libs文件夹,然后右键将libs设置成库文件夹
    2、注册驱动
        mysql5.0之后可以不注册驱动,在jar包里有某个文件存储着驱动类的名字
    3、获取连接
        如果连接本机可以省略IP
    获取执行sql的对象Statement
        createStatement()
        prepareStatement()
        管理事务
            开启事务setAutoCommit(boolean commit)
            提交事务commit()
            回滚事务rollback()
        Statement
            execute() 了解即可
            executeUpdate() 执行DML语句(增删改)、DDL语句(定义表和库)
            其返回值int类型表示影响的行数,我们可以通过返回值判断语句是否执行成功,如果返回值大于0,则执行成功,反之执行失败
            executeQuery() 执行DQL语句(查询语句)
            其返回值为一个结果集ResultSet对象            
            在finally中关闭Statement要先判断是否为空
    4、定义sql语句

JDBC代码实现


public static void main(String[] args) throws Exception {
    Class.forName("com.mysql.jdbc.Driver"); //注册驱动
    String url="jdbc:mysql://localhost:3306/db3[?characterEncoding=utf8]";
    //可以在url后面追加参数设置编码方式
    String userName = "root";
    String password = "root";
    Connection conn = DriverManager.getConnection(url,userName,password);
    //获取连接对象
    Statement stmt = conn.createStatement();
    //获取sql执行对象
    String sql = "update emp set salary = 8000 where id = 1001";
    int result = stmt.executeUpdate(sql);
    //执行sql语句
    System.out.println(result);
    stmt.close();
    conn.close();
    //关闭资源
}

executeQuery()
ResultSet 结果集对象 封装查询结果
next() 两个功能:①游标向下移动一行,②并判断下一行是否有数据,返回布尔值
getXxx(参数) 获取Xxx类型数据
    参数一:int类型 代表字段编号 从1开始
    参数二:String类型 代表字段名
ResultSet也需要关闭
使用步骤:
    ①游标向下移动一行    next()
    ②判断是否有数据    同上
    ③获得数据  rs.get("列名")

自定义JDBC工具类
        将url、name、password、driver等参数存放在jdbc.properties配置文件中,使用Properties来读取文件
        为方便程序使用,其中,配置文件的路径可以使用两种方式获得:
        ①通过类加载器ClassLoader的getResource("文件名")获取配置文件路径

ClassLoader classLoader = DBUtils.class.getClassLoader(); //获得类加载器
URL res= classLoader.getResource("文件名"); //使用ClassLoader搜索,默认搜索根路径是src
//使用类加载器可以根据文件名找路径的特性找到配置文件的URL
String path= res.getPath(); //通过URL找到配置文件的绝对路径
props.load(new FileReader(path));
        ②通过class对象的getResourceAsStream("文件名")来直接返回通往配置文件的输入流

prop.load(DBUtils.class.getResourceAsStream("文件名"));
//与上面不同的是,默认从当前类同包下搜索
//获取和DBUtils类同包下指向jdbc.properties文件的InputStream流
//注意,参数里接收的是路径名,"jdbc.properties"表示当前类同路径下的文件
//如果想寻找src路径下的文件,需要在前方加斜杠/
prop.load(DBUtils.class.getResourceAsStream("/jdbc.properties"));
//斜杠表示根目录(根目录是src)

注意:
1、每个类加载器都有自己的预定义的搜索范围,因此一般使用同一个工程下的类的类加载器查找配置文件的路径
2、Class和ClassLoader都有getResource("文件名或路径")搜索文件的功能,但是有细微差别,Class默认从当前类包下开始搜(除非前缀/才会从src下搜索),而ClassLoader会默认从src下进行搜索

sql注入 a' or 'a' = 'a
PreparedStatement
预编译:参数使用占位符?替代
sql的参数使用?作为占位符
例如:select * from user where name=? and password=?
setXxx(参数1,参数2)
    参数1:?的位置
    参数2:?的值

优点:1、防止sql注入
          2、效率更高

JDBC控制事务
使用Connection对象来管理事务
    开启事务setAutoCommit(boolean commit) //设置参数为false,即开启事务
    提交事务commit()
    回滚事务rollback()




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