第一天数据库概念
数据库的历史
层级模型
网状模型
关系模型(重点)
关系-对象模型
关系型数据库的代表
MySQL数据库(要学习的):开源数据库,属于中型数据库,实际上可以满足现市场上的大部分数据存储要求。
Oracle数据库:不开源(学习免费),属于大型数据库,事务安全级别比较高,对数据安全性和性能要求较高的行业需要使用。
DB2:不开源,属于大型数据库,属于IBM公司
Sql Server:跟mysql一样,属于开源的中型数据库
sqlite:小型的数据库,一般运用在移动端和嵌入式
Access:小型的数据库,一般运用在移动端和嵌入式
mysql的安装和配置
下载mysql数据库
下载地址:https://dev.mysql.com/downloads/mysql/
解压文件之后,需要在文件夹里面新建一个my.ini文件。该文件中配置的是全局的配置参数,比如:编码集、端口、数据文件夹、最大连接数等参数。
参数配置如下:
[mysql]# 设置数据库的默认全局编码集default-character-set=utf8[mysqld]# 设置数据库的端口port=3306# 设置数据库的文件夹basedir=D:\mysql\mysql-8.0.22-winx64\mysql-8.0.22-winx64# 设置数据库中实际数据存储的文件夹(该文件夹用来存储数据的)datadir=D:\mysql\mysql-8.0.22-winx64\mysql-8.0.22-winx64\data# 设置数据库的最大链接数max_connections=20# 设置服务端的编码character-set-server=utf8# 数据库的引擎设置default-storage-engine=INNODB
配置环境变量(才能在任何地方打开数据库的命令)
使用命令行进行安装数据库,一般电脑会提示使用管理员进行使用命令
可能会存在提示缺少vcruntime140_1.dll文件,只需要先去下载,然后将该文件放置在c盘下面的System32文件夹里面和SysWOW64文件夹中。
再回到命令行输入命令:mysqld -install
如果出现命令内容为:Service successfully installed.,说明安装成功
使用命令找到安装数据库的密码并记录,后续登录需要使用
在命令行中继续使用命令:mysqld —initialize —console
这里需要些许时间等待,找到A temporary password is generated for root@localhost: Cm8lKQ&wjzvB,冒号后面为默认的安装密码。
使用命令开启数据库的服务
在命令行输入命令:net start mysql 如果出现:MySQL 服务已经启动成功。说明服务启动成功
使用命令登录数据库
在命令行输入命令:mysql -uroot -p
如果出现以下图示,说明登录成功
因为默认的密码太过于复杂,需要重置密码
在命令行输入命令,先输入:use mysql
再输入:ALTER USER ‘root’@’localhost’ IDENTIFIED WITH mysql_native_password BY ‘root’
第二天一、mysql命令
1.1 mysql的基础命令
登录命令:如果在命令行出现了mysql>说明登录成功
— 会有警告提示,密码是明文的mysql-uroot-p密码— 第二种,在命令行只输入mysql-uroot-p—回车— 会提示输入密码,现在输入密码,是保密的。enter password:— 对于mysql完整的登录命令 -p密码,-P端口 -h主机名mysql-uroot-p密码-P3306-h127.0.0.1
退出mysql:
mysql>exit;
查看mysql数据库管理系统中的所有数据库
— 查看所有的数据库mysql>SHOW DATABASES;
一般对于刚刚安装的数据库,会有默认的四张表,这四张表能不能删除
使用指定的数据库
mysql>USE 库名;
查看数据库中所有的表
mysql>SHOW TABLES;
二、数据库结构化查询语句SQL
DDL:数据库定义语言,包含:数据库的创建、数据表的创建、删除数据库、删除数据表、修改数据表。
DML:数据库操作语言,包含:新增数据、删除数据、修改数据
DQL:数据库查询语言,包含:查询数据
DCL:数据库控制语言,用来给组员进行分发权限的
TCL:事务控制语言
2.1 数据库定义语言DDL
使用命令行创建数据库
mysql>CREATEDATABASE 数据库名;
删除数据库命令
DROPDATABASE db_shop;
创建数据库中的表:需要表中的字段,规定字段数据类型
— 先选择到指定的数据库USE 数据库名;— 创建表CREATETABLEt_student(s_idint,s_namevarchar(30),ageint,genderchar);
查看指定数据库中所有的表
mysql>SHOW TABLES;
查看指定表中的表结构
mysql>DESCt_student;
删除一张表
mysql>DROPTABLEt_student;
复制一张表(只复制结构,不复制数据)
mysql>CREATETABLEstudentLIKEt_student;
复制一张表,要将数据和结构一起赋值,下午再验证
mysql>CREATETABLEstuAS(SELECT*FROMt_student);
向表中新增一个字段
mysql>ALTERTABLEt_student ADD COLUMN telVARCHAR(11);
修改表中已经存在字段的数据类型
mysql>ALTERTABLEt_student modify genderVARCHAR(10);
删除表中的字段
mysql>ALTERTABLEt_studentDROPgender;
2.2 数据库操作语言DML
向数据库中新增数据
— 新增语句:INSERT INTO 表名(字段) value(值);INSERT INTO t_student(s_id,s_name,age,tel) value(1,”李四”,18,”1100”);— 如果只有部分数据需要写,那么就新增部分数据即可INSERT INTO t_student(s_id,s_name) value(2,”张三”);INSERT INTO t_student(s_id,age) value(3,19);— 如果所新增的数据和表中的字段完全一致(新增的数据和表中字段的个数一致),表名后面可以不跟括号INSERT INTO t_student value(4,”王五”,20,”1200”);
修改数据
— 修改数据:UPDATE 表名 SET 字段 = 值;一般是不试用的这种方式,一次性将所有行中对应列的数据修改UPDATEt_studentSETage=10;— 根据条件修改数据:UPDATE 表名 SET 字段 = 值 WHERE s_id = 值;常用方式,根据主键修改指定行的数据UPDATEt_studentSETage=18WHEREs_id=1;— 一次性修改多个字段的值UPDATEt_studentSETage=28,tel=’1300’WHEREs_id=2;
删除数据
— 删除数据:DELETE FROM 表名;禁止使用DELETEFROMt_student;— 根据条件删除数据DELETEFROMt_studentWHEREs_id=1;
2.3数据库查询语言DQL(最简单的)
— 单表简单查询:SELECT FROM 表名,SELECT FROM t_student;
三、数据类型
3.1 数据库的数据类型
整型
int:最常用的整型
smallint:短整型
bigint:长整型
mediumint:中等整型
tinyint:微整型
浮点型
double:双精度浮点型
float:单精度浮点型
decimal(D,M):定点小数
字符型
char:定长的字符型
varchar:变长的字符型
两者的区别:char因为是定长的,不管存储的数据长度是多少,都直接给255内存大小,会一定的浪费空间,因为不需要计算开辟的空间大小,节约时间
varchar:因为是变长的,需要执行两次,第一次计算实际需要的内存空间,第二次才会真正的存储数据,会节约内存大小,会消耗时间,一般在设置varchar类型的时候,会给指定长度,用来限制最大空间。
字节类型(了解)
BLOB:字节类型
BIGBLOB:大字节文件
文本类型
text
时间
time:时间
datatime:时间
year:年
四、数据库设计
4.1 键
唯一键:能够唯一识别出一行数据的字段称为唯一键,比如:学号、电话、身份证等。(了解)
主键:从唯一键中选出作为识别一行数据的字段称为主键,一般将id设置主键
候选键:从唯一键中,除了主键的字段,其余字段称为候选键(了解)
外键:一般用来关联表与表中的关系,一个表中的外键,都是另外一张表中主键的值,添加上外键之后,不能在该外键字段中添加除了另外一张表中主键以外的值,如果在外键中使用了数据,另外一张表的对应的主键数据,不能删除。
4.2 约束
主键约束:如果将一个字段设置为主键,那么数据库会自动识别是否重复,如果重复将不能存入。主键约束的关键在于不能重复。一般情况下,会将主键设置为自增。
外键约束:一个表中外键字段的值,只能是另一一张表中主键存在的值。表与表之间的关系
非空约束:如果一个字段设置为非空约束,那么该字段必须有值,不能为null
默认值:给指定的字段设置默认值,在新增的时候,如果没有给该字段添加数据,则数据库会自动将默认值填充在该位置。
自定义约束:用触发器、存储过程或者函数代码实现约束。
4.3 范式
第一范式:保证列的原子性
第二范式:保证每一个实体能够被唯一区分出来,可以使用主键来满足第二范式
第三范式:保证每一个实体的字段都和主键直接相关,而不是间接相关,如果有相关的数据信息,使用外键进行关联
第三天表与表之间的关系(补)
概念:表与表之间的关系,在理解上,一张表中的数据对应另外一张表中的数据关系,从每一行理解。
一对一关系一对多关系多对多关系一、数据库查询语句DQL
/Navicat MySQL Data TransferSource Server : localhostSource Server Version : 80022Source Host : 127.0.0.1:3306Source Database : db_schoolTarget Server Type : MYSQLTarget Server Version : 80022File Encoding : 65001Date: 2020-12-23 14:47:16/SETFOREIGN_KEY_CHECKS=0;— ——————————————— Table structure for course— ——————————————DROPTABLEIF EXISTS course
;CREATETABLEcourse
(c_id
varchar(20)NOTNULL,c_name
varchar(20)NOTNULLDEFAULT’’,t_id
varchar(20)NOTNULL,PRIMARY KEY(c_id
))ENGINE=InnoDB DEFAULT CHARSET=utf8;— ——————————————— Records of course— ——————————————INSERTINTOcourse
VALUES(‘01’,’语文’,’02’);INSERTINTOcourse
VALUES(‘02’,’数学’,’01’);INSERTINTOcourse
VALUES(‘03’,’英语’,’03’);— ——————————————— Table structure for score— ——————————————DROPTABLEIF EXISTS score
;CREATETABLEscore
(s_id
varchar(20)NOTNULL,c_id
varchar(20)NOTNULL,s_score
intDEFAULTNULL,PRIMARY KEY(s_id
,c_id
))ENGINE=InnoDB DEFAULT CHARSET=utf8;— ——————————————— Records of score— ——————————————INSERTINTOscore
VALUES(‘01’,’01’,’80’);INSERTINTOscore
VALUES(‘01’,’02’,’90’);INSERTINTOscore
VALUES(‘01’,’03’,’99’);INSERTINTOscore
VALUES(‘02’,’01’,’70’);INSERTINTOscore
VALUES(‘02’,’02’,’60’);INSERTINTOscore
VALUES(‘02’,’03’,’80’);INSERTINTOscore
VALUES(‘03’,’01’,’80’);INSERTINTOscore
VALUES(‘03’,’02’,’80’);INSERTINTOscore
VALUES(‘03’,’03’,’80’);INSERTINTOscore
VALUES(‘04’,’01’,’50’);INSERTINTOscore
VALUES(‘04’,’02’,’30’);INSERTINTOscore
VALUES(‘04’,’03’,’20’);INSERTINTOscore
VALUES(‘05’,’01’,’76’);INSERTINTOscore
VALUES(‘05’,’02’,’87’);INSERTINTOscore
VALUES(‘06’,’01’,’31’);INSERTINTOscore
VALUES(‘06’,’03’,’34’);INSERTINTOscore
VALUES(‘07’,’02’,’89’);INSERTINTOscore
VALUES(‘07’,’03’,’98’);— ——————————————— Table structure for student— ——————————————DROPTABLEIF EXISTS student
;CREATETABLEstudent
(s_id
varchar(20)NOTNULL,s_name
varchar(20)CHARACTERSETutf8 COLLATE utf8_general_ci DEFAULT’’,s_birth
varchar(20)CHARACTERSETutf8 COLLATE utf8_general_ci DEFAULT’’,s_sex
varchar(10)CHARACTERSETutf8 COLLATE utf8_general_ci DEFAULT’’,age
intDEFAULTNULL,height
intDEFAULTNULL,PRIMARY KEY(s_id
))ENGINE=InnoDB DEFAULT CHARSET=utf8;— ——————————————— Records of student— ——————————————INSERTINTOstudent
VALUES(‘01’,’赵雷’,’1990-01-01’,’男’,’23’,’160’);INSERTINTOstudent
VALUES(‘02’,’钱电’,’1990-12-21’,’女’,’26’,’165’);INSERTINTOstudent
VALUES(‘03’,’孙风’,’1990-05-20’,’男’,’20’,’155’);INSERTINTOstudent
VALUES(‘04’,’李云’,’1990-08-06’,’保密’,’19’,’180’);INSERTINTOstudent
VALUES(‘05’,’周梅’,’1991-12-01’,’女’,’22’,’175’);INSERTINTOstudent
VALUES(‘06’,’吴兰’,’1992-03-01’,’女’,’18’,’167’);INSERTINTOstudent
VALUES(‘07’,’郑竹’,’1989-07-01’,’男’,’24’,’158’);INSERTINTOstudent
VALUES(‘08’,’王菊’,’1990-01-20’,’女’,’25’,’176’);INSERTINTOstudent
VALUES(‘09’,’李云龙’,’1990-01-20’,’男’,’26’,’163’);— ——————————————— Table structure for teacher— ——————————————DROPTABLEIF EXISTS teacher
;CREATETABLEteacher
(t_id
varchar(20)NOTNULL,t_name
varchar(20)NOTNULLDEFAULT’’,PRIMARY KEY(t_id
))ENGINE=InnoDB DEFAULT CHARSET=utf8;— ——————————————— Records of teacher— ——————————————INSERTINTOteacher
VALUES(‘01’,’张三’);INSERTINTOteacher
VALUES(‘02’,’李四’);INSERTINTOteacher
VALUES(‘03’,’王五’);
1.1简单查询语句
简单查询
— 1、使用查询语句,将一张表中所有的数据查询出来SELECTFROMstudent;(不推荐使用,在开发里面,禁止使用)— 推荐在查询的时候,用字段名称替换,字段名可以只写部分SELECTsid,s_name,s_birth,s_sex,ageFROMstudent;
条件查询:需要使用到关键字WHERE
— 1、根据id值查询指定的学生数据,结果集只有一条SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_id=1;— 2、查询性别为男的所有学生数据,结果集有多条SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_sex=”男”;— 3、多条件查询,多个条件一起查询,会使用到逻辑运算符,比如:查询小于20岁的所有男学生SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_sex=”男”ANDage<20;-- 4、多条件查询,多个条件一起查询,比如:查询所有的男学生,或者年龄小于20的SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_sex="男"ORage<20;-- 5、如果使用or条件,一定要注意sql注入SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_sex="男"OR1=1;-- 6、查询出性别不等于男,会将女学生或者保密的学生SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_sex<>“男”;— 7、使用条件选定范围内的数据,不如查询出年龄在18到22岁之间的学生SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREage>18ANDage<22;-- 8、选择一定范围内的数据可以使用关键字between,两端数据都包含SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREagebetween18AND22;
模糊查询,需要使用到关键字like,在实际开发中,为了提高数据库的查询效率,要尽量避免使用模糊查询,
— 如果要使用模糊查询,需要使用到占位符:和%— 表示单个占位符— % 多个占位符— 使用模糊查询,将姓李的所有学生查询出来SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_nameLIKE”李“;— 使用模糊查询,查询出名字中有李的名称SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentWHEREs_nameLIKE”李%”;
排序查询:有一些字段,可以通过对其进行排序查询结果,排序分为升序和降序,要用到关键字ORDER BY
— 排序语法:SELECT 字段 FROM 表 ORDER BY 要排序的字段 排序规则(ASC升序,DESC降序,默认升序)— 按照学生的年龄进行升序排列SELECTs_id,s_name,s_birth,s_sex,ageFROMstudentORDERBYageASC;— 按照学生的身高,降序排列SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentORDERBYheightDESC;
分组查询,在一个表中,按照特定的字段进行分组,要使用到关键字GROUP BY
— 5.7以后处理group by问题,在my.ini文件中,添加上配置参数:[msyqld]sql_mode=’STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION’— 查询成绩表,根据学号分组SELECTs_id,c_id,s_scoreFROMscoreGROUPBYs_id;— 在分组查询中,要使用聚合函数,分组才有意义,聚合函数都是放在SELECT关键字后面— 1、查询出一个分组中某一个字段的和:SUM(字段名)— 2、查询出一个分组中某一个字段的平均数:AVG(字段名)— 3、统计出某一个分组的数据个数:COUNT(字段名)— 4、查询出一个分组中某一个字段的最大值:MAX(字段名)— 5、查询出一个分组中某个字段的最小值:MIN(字段名)— 查询出每个学生的总成绩SELECTs_id,SUM(s_score)FROMscoreGROUPBYs_id;— 查询出每个学生的平均成绩SELECTs_idAS学号,AVG(s_score)FROMscoreGROUPBYs_id;— 统计出每个学生学了多少门课程SELECTs_idAS学号,COUNT(c_id)AS课程数FROMscoreGROUPBYs_id;— 通过sum函数和count函数计算平均成绩SELECTs_idAS学号,SUM(s_score)/COUNT(c_id)AS平均成绩FROMscoreGROUPBYs_id;— 找出该学生的最高成绩SELECTs_idAS学号,MAX(s_score)FROMscoreGROUPBYs_id;— 找出该学生的最低成绩SELECTs_idAS学号,MIN(s_score)FROMscoreGROUPBYs_id;— 找出平均成绩高于60分的学生,如果是把聚合函数的结果作为条件再次筛选,则需要用关键字HAVING,并且放在GROUP BY后面SELECTs_idAS学号,AVG(s_score)AS平均成绩FROMscoreGROUPBYs_idHAVINGAVG(s_score)>60;— 将聚合函数的结果作为排序的条件SELECTs_idAS学号,SUM(s_score)AS总成绩FROMscoreGROUPBYs_idORDERBYSUM(s_score)DESC;
筛选个数,需要使用关键字LIMIT,在分页的时候会使用到
— 从查询的结果集中,只要其中的几条数据,— 语法:LIMIT 起始位置(从0开始计数),查询的条数;SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentLIMIT0,5;
去重:会使用关键字DISTINCT,作用是将查询结果集中的某些字段的重复数据只保留一个
— 查询成绩表,根据学号进行去重。比如:查询出那些学生是有成绩的SELECTDISTINCTs_idFROMscore;
1.2 查询语句的执行顺序
一条完整的查询语句
SELECTDISTINCT字段FROM表名WHERE字段条件GROUPBY字段HAVING聚合函数条件ORDERBY字段 排序规则LIMIT起始位置,显示条数;
执行FROM,将硬盘中的数据放到内存中
执行JOIN ….ON
执行WHERE,将普通字段的条件进行筛选
查询语句中是否有GROUP BY,如果有按照规则分组,如果没有,则默认分为一个组
查询语句中,是否有HAVING,如果有将聚合函数作为条件,进行筛选
执行SELECT,将要查询的结果的字段挑选出来
执行DISTINCT将结果中重复的数据只显示一个
执行ORDER BY,如果没有,则按照升序排列
筛选LIMIT
1.3 子查询
可以实现多表查询,将一个表查询的结果,作为另外一张表的条件,进行查询
— 第一步:查询出总成绩最高的学生学号SELECTs_idAS学号FROMsocreGROUPBYs_idORDERBYSUM(S_SCORE)DESCLIMIT0,1;— 第二步:查询出01学号学生的所有信息SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_id=’01’;— 如果已知条件就是两张表,要求查询出总成绩最高的学生的信息SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_id=(SELECTs_idFROMscoreGROUPBYs_idORDERBYSUM(s_score)DESCLIMIT0,1);— 查询出有成绩的学生的信息SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_idin(SELECTDISTINCTs_idFROMscore);— 查询出没有成绩的学生信息SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_idnotin(SELECTDISTINCTs_idFROMscore);— 查询出平均成绩高于60分的学生信息SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_idIN(SELECTs_idFROMscoreGROUPBYs_idHAVINGAVG(s_score)>60);— exists:子查询语句中有结果,则主查询语句执行,如果子查询语句中没有结果,则主查询语句不执行。— 举例:SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREEXISTS(SELECTs_idFROMscoreWHEREs_score=100);
1.4 链接查询
一些复杂的查询语句,在一张表中并不能查询出结果,多表一起查询,使用链接查询将有关系的表进行连接,链接成一张表,然后在用筛选、分组、排序等进行操作。
— 交叉链接:因为会产生笛卡尔积,因此禁止使用— 举例:查询所有学生的信息及学生对应的成绩SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,c_id,s_scoreFROMstudentASs1,scoreASs2WHEREs1.s_id=s2.s_id;— 内连接:……FROM 表1 INNER JOIN 表2 ON 主外键链接条件— 举例:查询所有学生的信息及学生对应的成绩SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,c_id,s_scoreFROMstudentASs1 INNERJOINscoreASs2ONs1.s_id=s2.s_id;— 内连接举例:查询出所有学生学习的课程信息及对应的成绩SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,s2.c_id,s_score,c.c_id,c_name,t_idFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcourseAScONs2.c_id=c.c_id;— 在上面的基础上, 可以继续进行筛选,查询出所有学生中成绩最高的学生信息、课程信息和成绩SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,s2.c_id,s_score,c.c_id,c_name,t_idFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcourseAScONs2.c_id=c.c_idORDERBYs_scoreDESCLIMIT0,1;— 查询出所有老师教的所有课程的所有成绩的所有学生信息SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,s2.c_id,s_score,c.c_id,c_name,c.t_id,t.t_id,t_nameFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcourseAScONs2.c_id=c.c_idJOINteacherAStONc.t_id=t.t_id;— 外连接:左外连接和右外连接— 左外连接:以左边的表为基准,右边的表如果对应的没有数据,则用null来表示,左边的表一定要有数据,语法:FROM 表1 LEFT JOIN 表2 ON 条件。SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,c_id,s_scoreFROMstudentASs1 LEFTJOINscoreASs2ONs1.s_id=s2.s_id;— 右外连接— 以右边的表为基准,左边的表如果对应的没有数据,则用null来表示,右边的表一定要有数据,语法:FROM 表1 RIGHT JOIN 表2 ON 条件。SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.s_id,c_id,s_scoreFROMstudentASs1 RIGHTJOINscoreASs2ONs1.s_id=s2.s_id;
第四天一、数据库查询练习1.1 第一部分
— 1、查询出平均成绩大于60分的学号、姓名和平均成绩,— 分析:条件为平均成绩过滤,会用到分组和having,学号和姓名在student表中,平均成绩在score表中,并且这两张表存在关联。优先考虑链接查询。SELECTs1.s_id,s_name,AVG(s_score)FROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idGROUPBYs1.s_idHAVINGAVG(s_score)>60;— 2、查询出平均成绩小于60分的学号、姓名和平均成绩,但是要包含没有成绩的学生— 分析:过滤聚合函数的条件,要使用分组和HAVING,需要使用到student和score,并且两种表有关联,直接先使用链接查询,因为需要没有成绩的学生信息也显示出来,考虑使用左外连接SELECTs1.s_id,s_name,s_score,AVG(s_score)FROMstudentASs1 LEFTJOINscoreASs2ONs1.s_id=s2.s_idGROUPBYs1.s_idHAVINGAVG(s_score)<60ORs_scoreISNULL;-- 3、查询出所有学生的学生编号、姓名、选课总数、每个学生的总成绩-- 分析:学生编号和姓名在学生表中,选课总数和总成绩在成绩表中,因为要用到聚合函数,需要使用分组,需要用到student表和score表,直接链接查询,没有成绩的学生没有要求选择出来,不考虑SELECTs1.s_id,s_name,COUNT(c_id),SUM(s_score)FROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idGROUPBYs1.s_id;-- 4、查询出学过张三老师课程的学生信息-- 分析:已知条件老师的姓名=张三,要查询的结果:学生信息(学号、姓名、年龄、生日、身高等),-- 第4题第一种方式:子查询-- 第一步:先根据老师的姓名查询出老师的t_id,SELECTt_idFROMteacherWHEREt_name="张三";-- 第二步:根据查询出来的老师t_id,在course表中查询出相应的课程c_idSELECTc_idFROMcourseWHEREt_id=....-- 第三步:根据查询出来的课程c_id,在score表中出那些学生有相关课程的成绩。SELECTs_idFROMscoreWHEREc_idIN(....);-- 第四步:根据成绩表中查询出来的s_id,在student表中查询出来。SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idIN(......)-- 将四个步骤总结出一句sql命令SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idIN(SELECTs_idFROMscoreWHEREc_idIN(SELECTc_idFROMcourseWHEREt_id=(SELECTt_idFROMteacherWHEREt_name="张三")));-- 第4题的第二种方式:链接查询SELECTs1.s_id,s_name,s_sex,s_birth,age,heightFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcourseAScONs2.c_id=c.c_idJOINteacherAStONc.t_id=t.t_idWHEREt_name="张三";-- 5、查询出没有学过张三老师课程的学生信息,包括没有成绩的学生-- 分析:和第四题分析一样,最后是not in,包括没有成绩的学生-- 子查询方式:SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idNOTIN(SELECTs_idFROMscoreWHEREc_idIN(SELECTc_idFROMcourseWHEREt_id=(SELECTt_idFROMteacherWHEREt_name="张三")));-- 链接查询方式SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idNOTIN(SELECTDISTINCTs1.s_idFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcourseAScONs2.c_id=c.c_idJOINteacherAStONc.t_id=t.t_idWHEREt_name="张三");-- 6、学习过编号为01课程号并且也学过编号为02课程号的学生信息-- 分析:在成绩表中,用条件查询SELECTs_idFROMstudentASs1WHEREs_idin(SELECTs_idFROMscoreASs2WHEREs2.c_id="01")ANDs2.s_idIN(SELECTs_idFROMscoreASs3WHEREs3.c_id="02");-- 第二种:SELECTs_idFROM(SELECTs1.s_id,s_name,c_idFROMscoreASs1 LEFTJOINstudentASs2ONs1.s_id=s2.s_idWHEREs1.c_id="01")ASt1WHEREt1.s_idin(SELECTs1.s_id,s_name,c_idFROMscoreASs1 LEFTJOINstudentASs2ONs1.s_id=s2.s_idWHEREs1.c_id="02")GROUPBYt1.s_id;-- 7、查询出没有学全所有课程的学生编号,包括没有学过任何课程的学生-- 分析:需要查询课程表,统计出总共的课程数count(),因为是统计所有的课程数,不需要group by,再去成绩表中统计每个学生的课程数,如果小于该课程数,则表示没有学全,再将查询到的s_id在student表中进行过滤-- 第一步:统计课程表中的所有课程数:SELECTcount(c_id)FROMcourse;-- 第二步:查询出成绩表中每个学生的课程数SELECTs_idFROMscoreGROUPBYs_idHAVINGCOUNT(c_id)=.....;-- 第三步:去学生表中查询SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_idIN(......)-- 综合成一句sql命令SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_idNOTIN(SELECTs_idFROMscoreGROUPBYs_idHAVINGCOUNT(c_id)=(SELECTcount(c_id)FROMcourse));-- 8、查询出至少有一门课程与学号为01学生所学课程相同的学生信息-- 分析:查询出学号为01学生学过的所有课程号,再查询出哪些学生学过该课程-- 第一步:查询出01学生学过的课程号SELECTc_idFROMscoreWHEREs_id="01";-- 第二步:从成绩表中,查看哪些学生是学过01学生查询出来的课程SELECTs_idFROMscoreWHEREc_idIN(....)-- 第三步:查询学生信息SELECTs_id,s_name,s_birth,s_sex,age,hegithFROMstudentWHEREs_idIN(....)-- 综合成一句sql命令SELECTs_id,s_name,s_birth,s_sex,age,hegithFROMstudentWHEREs_idIN(SELECTs_idFROMscoreWHEREc_idIN(SELECTc_idFROMscoreWHEREs_id="01"))ANDs_id<>“01”;— 9、查询出成绩有两门以上不及格的学生信息— 分析:从成绩表中筛选出不及格的学生,再根据学生分组,用having统计课程数,选出大于2,再用子查询— 第一步:查询出不及格课程数大于2的学号SELECTs_idFROMscoreWHEREs_score<60GROUPBYs_idHAVINGCOUNT(c_id)>2;— 第二步:查询出学生SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_idIN(SELECTs_idFROMscoreWHEREs_score<60GROUPBYs_idHAVINGCOUNT(c_id)>2);— 10、查询出同一个学生学习课程01成绩比课程02成绩高的学生信息。SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idIN(SELECTs_idFROMscoreASs1WHEREc_id=”01”ANDEXISTS(SELECTs_idFROMscoreASs2WHEREs2.c_id=”02”ANDs1.s_id=s2.s_idANDs1.s_score>s2.s_score));
1.2 第二部分
— 1、查询出和学号为”01”学生学习课程完全相同的学生信息— 分析:先把01学生学过的课程全部查询出来,查询出其他学生学过的课程在01学生课程里面,并且学习的数量和01的数量一样— 第一步:查询出01学生学过的课程信息SELECTc_idFROMscoreWHEREs_id=”01”;— 第二步:从成绩表中,查询学过01学生相关课程的学生SELECTs_idFROMscoreWHEREc_idIN(……)— 第三步:根据学号分组,并且查询出每个学生的课程数SELECTs_idFROMscoreWHEREc_idIN(….)GROUPBYs_id;— 第四步:判断每个学生学习的数量是否和01学生学习的数量一样SELECTs_idFROMscoreWHEREc_idIN(…..)GROUPBYs_idHAVINGCOUNT(c_id)=(SELECTCOUNT(c_id)FROMscoreWHEREs_id=”01”);— 综合成一句sql命令SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idIN(SELECTs_idFROMscoreWHEREc_idIN(SELECTc_idFROMscoreWHEREs_id=”01”)GROUPBYs_idHAVINGCOUNT(c_id)=(SELECTCOUNT(c_id)FROMscoreWHEREs_id=”01”)ANDs_id<>”01”);— 2、查询出每个老师所授课程的总成绩,并按照降序排列— 分析:要查询总成绩,只能在成绩表中,查询每个老师的授课,需要关联课程表和老师表,使用内连接,最后完成排序SELECTs_id,s_score,s.c_id,c_name,t.t_id,t_name,SUM(s_score)AS总成绩FROMscoreASsJOINcourseAScONs.c_id=c.c_idJOINteacherAStONc.t_id=t.t_idGROUPBYt.t_idORDERBYSUM(s_score)DESC;— 3、查询出每门课程的学习学生数— 分析:将成绩表和课程表进行关联,然后根据课程id分组,统计学生SELECTc_id,c_name,COUNT(s_id)AS学习人数FROMscoreASsJOINcourseAScONs.c_id=c.c_idGROUPBYc.c_id;— 4、查询出1990年出生的学生信息— 分析:可以通过模糊查询SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREs_birthLIKE”1990%”;— 分析:1990-01-01,能够从字符串中提取出来年份,SELECTs_id,s_name,s_birth,s_sex,age,heightFROMstudentWHEREYEAR(s_birth)=”1990”;— 5、查询学习课程名为“数学”,并且分数低于60分的学生信息— 分析:需要连接学生表,成绩表和课程表SELECTs1.s_id,s_name,s_sex,s_birth,age,height,s2.c_id,s_score,c_nameFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcourseAScONs2.c_id=c.c_idWHEREc_name=”数学”ANDs_score<60;-- 6、查询学习过张三老师课程的学生中,成绩最高的学生信息-- 分析:已知条件老师姓名,需要teacher表,课程表关联成绩表,学生表,SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentASs1JOINscoreASs2ONs1.s_id=s2.s_idJOINcouseAScONs2.c_id=c.c_idJOINteacherAStONc.t_id=t.t_idWHEREt_name='张三'ORDERBYs_scoreDESCLIMIT0,1;-- 上面的方式没有考虑到并列最高成绩,-- 分析:首先查找张三老师所教课程中的最高成绩,再从成绩表中查询出和最高成绩相等的学生学号,SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREs_idIN(SELECTs_idFROMscoreWHEREs_score=(SELECTMAX(s_score)FROMscoreASs1JOINcourseAScONs1.c_id=c.c_idJOINteacherAStONc.t_id=t.t_idWHEREt_name="张三")ANDc_idIN(SELECTc_idFROMcourseAScJOINteacherAStONc.t_id=t.t_idWHEREt_name="张三"));-- 7、查询和学号为01学生同年的学生信息-- 分析:先将01学生的年份查询出来,然后再到学生表中查询是否有相等的SELECTs_id,s_name,s_sex,s_birth,age,heightFROMstudentWHEREYEAR(s_birth)=(SELECTYEAR(s_birth)FROMstudentWHEREs_id="01");-- 8、查询每个课程的及格率-- 分析:先查询出每个课程的及格人数,然后再和每个课程的总人数进行相除SELECTt2.con/count(t1.c_id)*100FROMscoreASt1JOIN(SELECTcount(c_id)AScon,c_idFROMscoreWHEREs_score>=60GROUPBYc_id)ASt2ONt1.c_id=t2.c_idGROUPBYt1.c_id;— 子查询方式:SELECTc1.c_name课程名,s2.s2_sc/s1.s1_sc及格率FROMcourse c1,(SELECTc_id s1_id,COUNT(c_id)s1_scFROMscoreGROUPBYc_id)s1,(SELECTc.c_ids2_id,COUNT(c.s_score)s2_scFROM(SELECTc_id,s_scoreFROMscoreWHEREs_score>60)cGROUPBYc.c_id)s2WHEREs1.s1_id=s2.s2_idANDs1.s1_id=c1.c_id;— 10、查询出每门课程的学生人数、总成绩、平均成绩及授课老师— 分析:需要将三张表链接到一起SELECTCOUNT(s_id)AS学生人数,SUM(s_score)AS总成绩,AVG(s_score)AS平均成绩,t_nameAS授课老师FROMscoreASsJOINcourseAScONs.c_id=c.c_idJOINteacherAStONc.t_id=t.t_idGROUPBYc.c_id;
第五天补充内容
ANY和ALL子查询
ANY:子查询,如果是大于ANY(查询语句),只需要大于子查询语句结果的最小值,如果是小于ANY(查询语句),只需要小于子查询语句结果的最大值。
— > ANY()SELECT_FROMstudentWHEREheight>ANY(SELECTheightFROMstudentWHEREs_id=”01”ORs_id=”02”ORs_id=”05”);— < ANYSELECT_FROMstudentWHEREheight
— > ALL()SELECT_FROMstudentWHEREheight>ALL(SELECTheightFROMstudentWHEREs_id=”01”ORs_id=”02”ORs_id=”06”);— < ALL()SELECT_FROMstudentWHEREheight
在日常开发中,有一些多表,要被频繁的要组合成一个表进行查询,每一次都需要使用链接,先将有关联的表链接起来,在做查询,现在可以使用视图,将有关联的表直接生成一张表,视图实际上是一张虚拟表,在查询的时候,可以当成单表查询,提高程序员的编写链接查询的效率。
注意点:
1)视图本身是一张虚拟表,所以对视图的操作只能查询和修改,删除和新增做不了。
2)在实际开发中,建议不适用。原因:视图依赖于原表,如果原表中字段做了修改,那么视图将损坏。
1.2 使用工具创建视图注意:如果在创建视图的时候,存在相同的字段,需要取别名,否则要报错二、数据库事务2.1 概念为了数据的安全和一致,将同一个业务的多条sql命令绑定到一个事务中,该事务所以的sql指令,要么全部成功,要么全部失效。2.2 图示2.3 事务的相关命令1)在数据库中,由系统变量autocommit进行控制自动提交事务,当客户端发送一条指令的时候,由该变量自动的发给数据库服务端commit指令,将数据最终写到数据库中。2)在数据库事务里面,commit表示将事务管理日志里面的数据更新到数据库中3)在数据库事务里面,rollback表示将事务管理日志里面已经做了修改的数据,全部清空,回到初始状态。建议rollback之后,再次commit。2.4 手动开启事务
在开发中,如果频繁的修改自动提交事务的系统变量值,相对比较麻烦,数据库提供了开启手动事务。需要的时候将事务开启。
开启手动事务。使用命令,一旦使用了手动开启事务,从开启之后,所有的sql命令不再主动提交事务,数据库服务端会等待提交。
— 开启事务:start transaction;— 开启事务命令的第二种方式begin;
提交事务
— 提交事务commit;
事务回滚,在手动开启事务之后,如果中间出现错误,需要回到初始状态,可以使用回滚,当执行rollback事务之后,手动开启的事务结束。如果是回滚到指定的回滚点,则事务不会提交。
— 事务回滚,rollback— rollback是回滚所有,可以设置回滚点,回滚到指定位置— 设置回滚点savepoint 回滚点名称;— 回滚到回滚点rollback to 回滚点名称;
2.5 数据库事务的特性(ACID)1)原子性:在一个事务之间,不可以再进行拆分,从开启事务到事务提交结束,期间是一个整体,不能再进行拆分。2)持久性:数据库事务一旦提交,会将数据提交到数据库中存储,直到下一次数据修改之前,都是一直存储数据的,在这期间,数据不会改变。3)隔离性:数据库事务是一个独立的整体, 相互之间不被影响。4)一致性:在事务执行前后,数据的状态是一致的。
三、数据库变量3.1 系统变量在数据库管理系统中,已经被定义好的变量,用来控制整个数据库,比如:控制自动提交事务的变量autocommit。对于系统变量,一般是不会设置的。
设置系统变量:SET @@变量名 = 值;
查看所有的系统变量:show variables;
通过模糊查询,查询出部分的系统变量:show variables like “%%”;
3.2 用户变量对于用户变量,也被称为会话变量、全局变量等,在定义该变量的时候,只有在该次链接才会生效,在其他链接中是不生效的。
设置全局变量:SET @变量名= “值”;
查询全局变量:SELECT @变量名;
修改全局变量:SET @变量名 = “值”;
3.3 局部变量该变量存储在局部的一些代码块中,比如:函数、存储过程、分支、循环等,局部变量一般存在begin和end之间。
局部变量的定义:DECLARE 变量名 数据类型 defalue 值;
查询局部变量:SELECT 变量名;
修改局部变量:SET 变量名 = 值;
四、结构化语句4.1 分支语句
— if分支语句的语法— 第一种:IF 判断语句 THEN当判断语句符合条件的时候,执行的语句END IF;— 第二种:IF 判断语句 THEN当判断语句符合条件的时候,执行的语句ELSE当判断语句不符合条件的时候执行的语句END IF;— 第三种:IF 判断语句 THEN当判断语句符合条件的时候,执行的语句ELSEIF 判断语句 THEN当判断语句符合条件的时候,执行的语句ELSE当所有的判断语句不符合条件的时候执行的语句END IF;4.2 循环语句
— 循环语句WHILE 判断语句 DO循环的代码;改变变量的值;END WHILE;— 跳出循环— leave:和java中的break作用一致,表示结束整个循环。— iterate:和java中的continue作用一致,表示结束本次循环,继续下一次循环。— 当有循环嵌套的时候,可以给循环标记,表示跳出指定循环。— 比如:WHILE 判断语句 DOLOOP1:WHILE 判断语句 DOWHILE 判断语句 DOIF 判断语句 THENLEAVE LOOP1;END IF;END WHILE;END WHILE;END WHILE;五、函数编程5.1创建函数
— 创建函数CREATEFUNCTION 函数名称(参数)RETURNS 返回值数据类型BEGIN编写函数的代码;END举例说明:计算两个数的和
— 创建函数CREATEFUNCTION fun1()RETURNSINTBEGIN— 定义两个变量DECLARE iINTDEFAULT10;DECLARE jINTDEFAULT20;— 定义一个变量,用于接受两个数的和DECLARE resINTDEFAULT0;— 计算两个数的和SETres=i+j;— 将计算的和返回RETURN res;END举例说明:计算任意两个数的和
CREATEFUNCTION fun1(aint,bint)RETURNSINTBEGINDECLARE resintdefault0;SETres=a+b;RETURN res;END举例说明:计算200以内的能被3整除的数相加和
— 创建函数CREATEFUNCTION fun2()RETURNSINTBEGIN— 定义变量DECLARE iINTDEFAULT1;— 定义变量,记录和DECLARE resINTDEFAULT0;— 使用循环WHILE i<=200DO— 判断能被3整除的数IF i%3=0THENSETres=res+i;END IF;— 修改变量的值SETi=i+1;END WHILE;— 返回值RETURN res;END举例说明:计算x的y次方
— 不考虑x为0的情况,但是要考虑y大于0,小于0和等于0的情况。5.2 查询函数:想要查看一下一个数据库中存在哪些函数。
— 查询所有的函数SHOW FUNCTION STATUS;— 查询自己的函数,可以使用模糊查询SHOW FUNCTION STATUSLIKE”%fun%”;5.3 调用函数
— 调用函数SELECT函数名();5.4 删除函数
DROPFUNCTION 函数名;
第六天一、存储过程1.1 创建存储过程
— 创建,关键字procedure,没有返回值数据类型,也没有返回值createprocedure 存储过程名称(参数列表)begin编写存储过程的名称;end1.2 查询存储过程
— 查询所有的存储过程show procedure status;— 查询自定义的存储过程,可以使用模糊查询show procedure statuslike”%%”;1.3 调用存储过程
— 调用call 存储过程名字();1.4 删除存储过程
— 删除dropprocedure 存储过程名称;1.5 存储过程参数问题
参数的形式:参数类型 参数名 数据类型
参数类型:
1)in:将存储过程外面的变量传递给存储过程里面使用
2)out:将存储过程里面的变量,传递给存储过程外面使用
3)inout:即可以将存储过程外面的值传递给里面使用,也可以将存储过程里面的值传递到外面。
举例说明
— 定义存储过程createprocedure pro2(inaint,out bint,inout cint)begin— 查询形式参数的值selecta,b,c;— 查询一次全局变量的值select@num1,@num2,@num3;— 设置形式参数a,b,c的值seta=10;setb=20;setc=30;— 查询一次形式参数的值selecta,b,c;— 再次查询全局变量select@num1,@num2,@num3;end图示
二、触发器2.1 创建触发器
— 创建触发器语法createtrigger 触发器名称 触发时机 触发事件on表名 for each rowbegin触发器的代码;end— 触发时机:AFTER、BEFORE— 触发事件:INSERT、UPDATE、DELETE— 一张表最多有6个触发器举例:购买商品生成订单
createtrigger tri2 afterinsertont_order for each rowbegin— 当触发器触发了,说明订单表中有了新增的数据,将相应的商品表数量的数据较少updatet_productsetnumber=number-new.buy_numberwherep_id=new.o_p_id;end2.2 查询触发器
— 查询触发器show triggers;2.3 删除触发器
— 删除droptrigger 触发器名称;
三、索引3.1 索引的概念索引:数据库除了为数据提供存储和查询的功能之外,还一并维护着具有特定结构数据结构容器,这些数据结构是为了给数据库提供高效的查询方式,而这些维护着的数据结构就称为索引;索引的本质是数据结构。图示3.2 索引的优缺点
优点:
1、会将要查询的字段生成索引,提高查询效率,降低数据库的IO资源。
2、在生成数据结构的时候,会对数据进行排序,省去排序的消耗。
缺点:
1、因为生成的索引只记录一个字段,已经将该实体的内容所在地址放到数据结构中,占用内存。
2、如果数据库做了增加、删除和修改的操作,数据库除了操作数据之外,还需要额外的维护相应的索引数据结构,因此降低增、删、改效率。
3.3 索引的分类1)BTree索引:对于mysql所有的存储引擎都支持BTree索引,mysql默认的存储引擎innoDB支持B+Tree树索引。2)Hash索引:支持该索引的存储引擎为Memory。3)R-Tree索引:支持该索引的存储引擎为MyISAM。4)Full-text索引:全文索引,存储引擎MyISAM支持,mysql默认存储引擎innoDB在版本5.7以后也支持。在mysql中,用的最多的是Btree索引,在默认存储引擎也是InnoDB。3.4 BTree索引分析图示3.5 索引的操作1)创建索引:
createindex 索引名称on表名(列名);2)查询索引
show indexfromt_user;3)刪除索引
dropindex ind1ont_user;
第七天一、数据库存储引擎
1.1 mysql的设计结构
图示
1.2 存储引擎的讲解
在mysql里面,存储引擎是以插件的形式存在的,存在多个存储引擎,程序员在使用的时候,可以根据需求选择存储引擎。对于存储引擎是在创建表的时候进行选择,存储引擎属于表的存储形式。作用于一个表。
特别提示:Oracle、sqlServer 只有一个唯一的存储引擎,而mysql有多个存储引擎,并且在5.5以前默认存储引擎MyISAM,在5.5以后选择InnoDB存储引擎。
想要查看目前安装的数据库中有哪些存储引擎可以使用:show engines;
1.3 MyISAM和InnoDB存储引擎的区别
- MyISAM存储引擎:不支持事务,不支持外键。
2)InnoDB存储引擎:支持事务,支持外键。
外键的补充
1)RESTRICT:如果主键所在的表中的数据被外键引用的数据所使用,那么该主键值不能进行修改。
2)NO ACTION:如果主键所在的表中的数据被外键引用的数据所使用,那么该主键值不能进行修改。
3)CASCADE:当主键所在表中,该数据被删除或修改了,那么关联表中对应的数据也将被删除和修改。
4)SET NULL:当主键所在的表中,该数据被删除或者修改了,那么关键表中的数据设置为null
二、数据库中的锁
mysql数据库在用户操作的过程中,除了传统资源,比如:CPU、ARM、IO资源(磁盘IO和网络IO),用户在操作的时候,会有并发的操作,并发操作会产生一些并发安全问题,通常都是通过上锁的方式。
2.1 锁的分类
根据粒度划分:
1)表锁:在操作的时候,会将整个表锁起来。
2)行锁:在操作的时候,会将一行数据锁起来。
根据操作划分:
1)读锁(共享锁):如果使用读锁,一旦将数据锁起来,其他用户只能读取,不能做增、删、改操作
2)写锁(排他锁):如果使用写锁,一旦将数据所起来,其他用户什么都做不了。
2.2 mysql的锁机制
对于mysql数据库,锁机制比较简单,不同的存储引擎有不同的锁支持
MyISAM引擎:只支持表锁,在mysql5.5以前,只有表锁,没有行锁。
InnoDB引擎:同时支持表锁和行锁。
对于表锁和行锁的特点
表锁:范围是作用在表上的,开销小、加锁快,粒度大,不会产生死锁。
行锁:范围作用在一行数据上,开销较大,加锁慢,粒度小,会产生死锁。在innoDB里面,默认加行锁。
2.3 MyISAM存储引擎的表锁
锁的开启
— 开启读锁locktable表名 read;— 开启写锁locktable表名 write;— 解锁unlock tables;
2.4 InnoDB存储引擎中的锁
InnoDB存储引擎支持表锁和行锁,但是,一般都是加行锁,行锁的特点:开销大,加锁慢,粒度小,会产生死锁,更加支持并发操作。对于InnoDB在操作的时候,会自动给增、删、改操作加上行锁,对于查询不加锁。
因为并发的操作,所以会引发一系列的并发事务。
1、丢失更新(脏写):多个事务同时操作同一个数据,第一个事务对数据做了修改,但是未提交到数据库中,第二个事务又对数据做了修改,未提交到数据库,谁后提交的数据库中,值就是后提交的。
2、脏读:多个事务同时操作同一个数据,第一个事务用于修改数据,未提交的时候,第二个事务进行查询数据,查询的仍然是修改前的数据。没有拿到最新的数据。
3、不可重复读:多个事务同时查询数据,在一定的时间段,根据相同的条件,所查询出来的数据和以前不一致。
4、幻读:读个事务同时查询数据,发现根据相同的条件查询,其他事务在此期间,可以查询出其他不相关的数据。
应对上述问题,数据库提出了隔离级别,进行避免以上问题。
隔离级别:提出来是解决并发问题, 隔离级别有4级,等级越高,发生错误的概率越低。消耗的资源将越高。隔离级别越高的表示破坏并发越强,因为隔离级别意味着串行化。串行化和并发相矛盾。
隔离级别:
1、read uncommitted
2、read committed
3、repeatable read
4、serializable
三、SQL优化初讲
1、将字段合理的添加为索引。
在索引的基础上,优化的考虑:
2、尽量避免使用模糊查询,如果避免不了模糊查询,尽量避免前置%
3、尽量避免使用in和not in,in子查询不会走索引查询。可以考虑between,或者其他子查询比如:exists
4、尽量避免使用or,or查询不走索引,仍然建议使用between。
5、尽量不要用having去过滤普通字段的条件。用where替换。
6、避免使用select*查询。
7、尽量不要查询多余的字段,最好是按需查询。
8、尽量不要让数据库中存在多余的null
9、尽量在数据库查询的时候,一些短的数据字段,不要用字符型,比较要使用=或者<>,建议用整型替换。
10、在查询语句中,不要将计算的运算符放在等号的左边,尽量使用在等号右边。
第八天一、JDBC讲解
1.1 JDBC的概念
JDBC(JAVA DASTABASE CONNECTION)是java提供的链接数据库的应用程序,使用java代码进行向数据库的服务端发送sql指令,并且完成事务操作的功能。
图示
1.2 JDBC主要类的介绍
Driver:JDBC的数据库驱动,表示选择哪个数据库进行连接操作。获取Driver使用的是DriverManager。
Connection:JDBC获取链接的对象,表示已经链接上之后获取的对象,获取链接由驱动管理完成,DriverManager.getConnection();该对象表示数据库的链接。
Statement:用来发送需要执行的SQL指令,并调用调用方法进行执行SQL指令,由Connection对象获取Statement对象,调用的是createStatement();方法进行获取对象。
PreparedStatement:是statement类的子类,比起statement更加优化,可以实现预编译对象。建议开发的时候使用该对象替换Satement对象。由Connection对象获取,调用PrepareStatement()方法获取。
涉及的方法:
1)execute():将SQL指令执行,不推荐使用,不区分是增、删、改还是查询。
2)executeQuery():将查询的SQL指令执行,当SQL用于查询的时候,使用该方法,返回值为ResultSet
3)executeUpdate():将增、删、改的SQL指令执行,当SQL用于修改数据的时候使用该方法,返回值为int,表示修改的行数。
ResultSet:表示执行完SQL指令后,获得的结果集存放的集合。
1.3 入门程序
/ DJBC的入门程序/publicclassDemo1{/ 主函数/publicstaticvoidmain(String[]args) {try{//1、注册驱动:将JDBC的应用程序关联起来加载,需要用到反射Class.forName(“com.mysql.jdbc.Driver”);/2、获取链接: url:表示链接数据库的url地址,链接本机为:jdbc:mysql://127.0.0.1:3306/数据库名 urse:数据库的用户名,一般自己的为root password:数据库的密码/Stringurl=”jdbc:mysql://127.0.0.1_school”;Stringuser=”root”;Stringpassword=”root”;Connectionconn=DriverManager.getConnection(url,user,password);//3、获取可以发送sql指令的对象Statementst=conn.createStatement();//4、编写sql语句,并执行Stringsql=”select from t_student”;ResultSetrs=st.executeQuery(sql);//5、通过结果集获取数据,编辑结果集ResultSetwhile(rs.next()) {//获取结果集中的数据//getInt(int columnIndex):取出结果中的第几列,不推荐//getInt(String columnLabel):取出字段名相同的数据,推荐方式intid=rs.getInt(“s_id”);System.out.println(“id = “+id);Stringname=rs.getString(“s_name”);System.out.println(“name = “+name);}//6、关闭资源,3个,先开的后关rs.close();st.close();conn.close();}catch(Exceptione) {e.printStackTrace();}}}
1.4 JDBC的示例代码
新增数据
/ @ClassName: InsertDemo @Description: JDBC新增的代码 @author Alon @date 2020年12月29日 上午11:15:56 /public class InsertDemo{public static void main(String[]args){try{//1、加载驱动Class.forName(“com.mysql.jdbc.Driver”);//在url里面需要处理编码集,不处理会出现乱码问题String url=”jdbc:mysql://127.0.0.1school?useUnicode=true&characterEncoding=utf-8”;String user=”root”;String password=”root”;//2、获取链接Connection conn=DriverManager.getConnection(url,user,password);//3、创建执行sql的对象,推荐使用预编译的对象,如果使用预编译对象,那么可以使用填充方式将参数填入String sql=”insert into t_student(s_name,s_age,s_sex) value(?,?,?)”;PreparedStatement ps=conn.prepareStatement(sql);//将?占位符替换ps.setString(1,”李四”);ps.setInt(2,20);ps.setString(3,”保密”);//4、执行sqlintrow=ps.executeUpdate();System.out.println(row);//5、关闭资源ps.close();conn.close();}catch(Exception e){e.printStackTrace();}}}
修改数据
/ @ClassName: UpdateDemo @Description: 更新数据的demo @author Alon @date 2020年12月29日 上午11:27:41 /public class UpdateDemo{public static void main(String[]args){try{//1、注册驱动Class.forName(“com.mysql.jdbc.Driver”);//2、获取链接String url=”jdbc:mysql://127.0.0.1_school?useUnicode=true&characterEncoding=utf-8”;String user=”root”;String password=”root”;Connection conn=DriverManager.getConnection(url,user,password);//3、获取预编译对象String sql=”update t_student set s_name = ? where s_id = ?”;PreparedStatement ps=conn.prepareStatement(sql);//替换占位符ps.setString(1,”李华”);ps.setInt(2,1);//4、执行sql语句introw=ps.executeUpdate();System.out.println(row);//5、关闭资源ps.close();conn.close();}catch(Exception e){e.printStackTrace();}}}
删除数据
/ @ClassName: DeleteDemo @Description: 删除数据的demo @author Alon @date 2020年12月29日 上午11:33:05 /public class DeleteDemo{public static void main(String[]args){try{//1、注册驱动Class.forName(“com.mysql.jdbc.Driver”);//2、获取链接String url=”jdbc:mysql://127.0.0.1_school?useUnicode=true&characterEncoding=utf-8”;String user=”root”;String password=”root”;Connection conn=DriverManager.getConnection(url,user,password);//3、获取预编译对象String sql=”delete from t_student where s_id = ?”;PreparedStatement ps=conn.prepareStatement(sql);//替换占位符ps.setInt(1,2);//4、执行sql指令introw=ps.executeUpdate();System.out.println(row);//关闭资源ps.close();conn.close();}catch(Exception e){e.printStackTrace();}}}
查询语句
/ @ClassName: QueryDemo @Description: 查询的demo @author Alon @date 2020年12月29日 上午11:37:15 _/public class QueryDemo{public static void main(String[]args){try{//1、注册驱动Class.forName(“com.mysql.jdbc.Driver”);//2、获取链接:String url=”jdbc:mysql://127.0.0.1_school?useUnicode=true&characterEncoding=utf-8”;String user=”root”;String password=”root”;Connection conn=DriverManager.getConnection(url,user,password);//3、获取预编译对象String sql=”select * from t_student where s_id = ?”;PreparedStatement ps=conn.prepareStatement(sql);ps.setInt(1,1);//4、执行sqlResultSet rs=ps.executeQuery();while(rs.next()){//获取值intsId=rs.getInt(“s_id”);String sName=rs.getString(“s_name”);intsAge=rs.getInt(“s_age”);String sSex=rs.getString(“s_sex”);System.out.println(“编号:”+sId+”,姓名:”+sName+”,年龄:”+sAge+”,性别:”+sSex);}//关闭资源rs.close();ps.close();conn.close();}catch(Exception e){e.printStackTrace();}}}1.5 封装JDBC方法
可以将注册驱动放到工具类中
2)可以将连接的方法放到工具类中
3)可以将关闭资源的方法放到工具类中,关闭资源有两种情况,因此最好使用重载。
/ @ClassName: JDBCUtils @Description: JDBC的工具类 @author Alon @date 2020年12月29日 下午2:16:08 /public class JDBCUtils{//将参数定义private static final String driver=”com.mysql.jdbc.Driver”;private static final String url=”jdbc:mysql://127.0.0.1school?useUnicode=true&characterEncoding=utf-8”;private static final String user=”root”;private static final String password=”root”;//静态代码块进行注册驱动static{try{Class.forName(driver);}catch(Exception e){e.printStackTrace();}}//提供一个公共的获取链接的方法public static Connection getConn(){//声明一个链接Connection conn=null;try{conn=DriverManager.getConnection(url,user,password);}catch(Exception e){e.printStackTrace();}return conn;}/ @Title: close @Description: 关闭资源 @param @param conn 链接 @param @param ps 预编译对象 @return void @throws /public static void close(Connection conn,PreparedStatement ps){try{if(ps!=null){ps.close();}if(conn!=null){conn.close();}}catch(SQLException e){e.printStackTrace();}}/ @Title: close @Description: 关闭资源,三种参数的重载形式 @param @param conn 链接对象 @param @param ps 预编译对象 @param @param rs 结果集对象 @return void @throws*/public static void close(Connection conn,PreparedStatement ps,ResultSet rs){try{if(rs!=null){rs.close();}}catch(Exception e){e.printStackTrace();}close(conn,ps);}}
1.6 深度分装JDBC
创建配置文件db.properties,要放在src目录下
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1_school?useUnicode=true&characterEncoding=utf-8user=rootpassword=root
思维:解决硬编码的问题,将参数用配置文件进行配置。
/ @ClassName: JDBCUtils2 @Description: 深度封装JDBC @author Alon @date 2020年12月29日 下午3:21:27 /public class JDBCUtils2{//声明四个变量private static String driver;private static String url;private static String user;private static String password;//使用静态代码块完成注册驱动以及读取properties文件内容。并将值读取后赋值给变量static{try{//读取properties文件//获取流InputStreamin=JDBCUtils2.class.getClassLoader().getResourceAsStream(“db.properties”);//创建Properties对象,该对象专门用来读取.properties类型的文件。Properties prop=new Properties();//将读取到文件的输入流加载到prop对象中prop.load(in);//获取值driver=prop.getProperty(“driver”);url=prop.getProperty(“url”);user=prop.getProperty(“user”);password=prop.getProperty(“password”);//注册驱动Class.forName(driver);}catch(Exception e){e.printStackTrace();}}/ @Title: getConn @Description: 获取链接 @param @return @return Connection 返回链接对象 @throws /public static Connection getConn(){try{return DriverManager.getConnection(url,user,password);}catch(Exception e){e.printStackTrace();}returnnull;}/ @Title: close @Description: 关闭资源 @param @param conn @param @param ps @return void @throws /public static void close(Connection conn,PreparedStatement ps){try{if(ps!=null){ps.close();}if(conn!=null){conn.close();}}catch(Exception e){e.printStackTrace();}}/ @Title: close @Description: 关闭资源,重载形式 @param @param conn @param @param ps @param @param rs @return void @throws _/public static void close(Connection conn,PreparedStatement ps,ResultSet rs){try{if(rs!=null){rs.close();}}catch(Exception e){e.printStackTrace();}close(conn,ps);}}
1.8 Druid连接池
目前市场主流的连接池
db.properties配置文件
driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1school?useUnicode=true&characterEncoding=utf-8username=rootpassword=rootinitialSize=10maxActive=300maxWait=60000
java文件
/ @ClassName: DruidUtils @Description: Druid连接池的工具类 @author Alon @date 2020年12月29日 下午5:15:13 /publicclassDruidUtils{privatestaticDataSourcedataSource;//声明一个连接池对象static{try{InputStreamin=DruidUtils.class.getClassLoader().getResourceAsStream(“db.properties”);Propertiesprop=newProperties();prop.load(in);dataSource=DruidDataSourceFactory.createDataSource(prop);}catch(Exceptione) {e.printStackTrace();}}/ @Title: getConn @Description: 获取链接 @param @return @return Connection @throws /publicstaticConnectiongetConn() {try{returndataSource.getConnection();}catch(Exceptione) {e.printStackTrace();}returnnull;}/ @Title: close @Description: 关闭资源 @param @param conn 数据库链接 @param @param ps 预编译对象 @return void @throws /publicstaticvoidclose(Connectionconn,PreparedStatementps) {try{if(ps!=null) {ps.close();}if(conn!=null) {conn.close();}}catch(SQLExceptione) {e.printStackTrace();}}/ @Title: close @Description: 关闭资源,三种参数的重载形式 @param @param conn 链接对象 @param @param ps 预编译对象 @param @param rs 结果集对象 @return void @throws _/publicstaticvoidclose(Connectionconn,PreparedStatementps,ResultSetrs) {try{if(rs!=null) {rs.close();}}catch(Exceptione) {e.printStackTrace();}close(conn,ps);}}
1.7c3p0连接池
配置文件及参数,名字必须是c3p0-config.xml,而且要放在src目录下
java代码
/ @ClassName: C3P0Utils @Description:c3p0连接池的工具类 @author Alon @date 2020年12月29日 下午4:39:46 /publicclassC3P0Utils{//声明并创建一个数据源//实际上ComboPooledDataSource()有参数,如果在配置文件中是default-config则不需要写名称//如果在配置文件中,不是default-config,则需要写名称privatestaticDataSourcedataSource=newComboPooledDataSource(“mysql-config”);publicstaticConnectiongetConn() {try{returndataSource.getConnection();}catch(Exceptione) {e.printStackTrace();}returnnull;}/ @Title: close @Description: 关闭资源 @param @param conn 数据库链接 @param @param ps 预编译对象 @return void @throws /publicstaticvoidclose(Connectionconn,PreparedStatementps) {try{if(ps!=null) {ps.close();}if(conn!=null) {conn.close();}}catch(SQLExceptione) {e.printStackTrace();}}/ @Title: close @Description: 关闭资源,三种参数的重载形式 @param @param conn 链接对象 @param @param ps 预编译对象 @param @param rs 结果集对象 @return void @throws*/publicstaticvoidclose(Connectionconn,PreparedStatementps,ResultSetrs) {try{if(rs!=null) {rs.close();}}catch(Exceptione) {e.printStackTrace();}close(conn,ps);}}