只会写代码,学好数据库,基本混饭吃
操作系统,数据结构与算法!开始搬砖
离散数学 数字电路 编译原理
4、数据库是所有软件体系中最核心的存在 DBA
DBMS(数据管理系统)
MySQL是一个关系型数据库管理系统
前世:瑞典MySQL AB公司
今生:属于Oracle旗下产品
MySQL是最流行的开放源码SQL数据库管理系统的应用软件之一
开源的数据库软件
体积小 速度快 总体拥有成本低 招人成本比较低 所有人必须会
中小网站 或者大型网站 集群!
官网:https://www.mysql.com/
安装建议
尽量不要使用exe 注册表 卸载的时候不方便
尽可能使用压缩包安装
网上教程贼多自己去找 也挺香的
安装步骤
1、下载后得到zip压缩包.
2、解压到自己想要安装到的目录,本人解压到的是D:\Environment\mysql-5.7.19
3、添加环境变量:我的电脑->属性->高级->环境变量
选择PATH,在其后面添加: 你的mysql 安装文件下面的bin文件夹
4、编辑 my.ini 文件 ,注意替换路径位置
[mysqld]
basedir=D:\Program Files\mysql-5.7\
datadir=D:\Program Files\mysql-5.7\data\
port=3306
skip-grant-tables
5、启动管理员模式下的CMD,并将路径切换至mysql下的bin目录,然后输入mysqld –install (安装mysql)
6、再输入 mysqld --initialize-insecure --user=mysql 初始化数据文件
7、然后再次启动mysql 然后用命令 mysql –u root –p 进入mysql管理界面(密码可为空)
8、进入界面后更改root密码
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
9、刷新权限
flush privileges;
10、修改 my.ini文件删除最后一句skip-grant-tables
11、重启mysql即可正常使用
net stop mysql
net start mysql
12、连接上测试出现以下结果就安装好了
一步步去做 , 理论上是没有任何问题的 .
如果您以前装过,现在需要重装,一定要将环境清理干净 .
好了,到这里大家都装好了,因为刚接触,所以我们先不学习命令.
这里给大家推荐一个工具 : SQLyog .
即便有了可视化工具,可是基本的DOS命名大家还是要记住!
可手动操作,管理MySQL数据库的软件工具
特点 : 简洁 , 易用 , 图形化
使用SQLyog管理工具自己完成以下操作 :
连接本地MySQL数据库
新建MySchool数据库
在历史记录中可以看到相对应的数据库操作的语句 .
连接数据库
打开MySQL命令窗口
连接数据库语句 : mysql -h 服务器主机地址 -u 用户名 -p 用户密码
注意 : -p后面不能加空格,否则会被当做密码的内容,导致登录失败 !
几个基本的数据库操作命令 :
update user set password=password('123456')where user='root'; 修改密码
flush privileges; 刷新数据库
show databases; 显示所有数据库
use dbname;打开某个数据库
show tables; 显示数据库mysql中所有的表
describe user; 显示表mysql数据库中user表的列信息
create database name; 创建数据库
use databasename; 选择数据库
exit; 退出Mysql
? 命令关键词 : 寻求帮助
-- 表示注释
mysql -u root -p --连接数据库
update mysql.user set authentication_string=password('123456') where user='root' and Host 'localhost';--修改用户密码
flush privileges;--刷新权限
----------------------------------------
--所有的语句都使用分号结尾
show databases;--查看所有的数据库
use 数据库名;--切换数据库
show tables;--查看数据库中所有的表
describe student;--查看表的信息
create database westos;--创建一个数据库 westos
exit;--退出连接
--单行注释(SQL本来的注释 有些地方也可以 用#)
/*
多行注释
*/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ai7vwJje-1596981632128)(mysqlnote.assets/image-20200801085707359.png)]
操作数据库>操作数据中的表>操作表中的数据
mysql的大小写不区分
CREATE DATABASE [IF NOT EXISTS] westos;
2、删除数据库
DROP DATABASE IF EXISTS westos;
3、使用数据库
use school
4、查看数据库
show dabases ;--查看所有的数据库
数值
字符串
时间日期
java.util.Date
null
-- 目标创建一个school数据库
-- 创建一个学生表(列 字段) 使用SQl创建
-- 学号 int 登录密码 varcahr(20) 姓名, 性别 varchar(2) 出生日期(datetime) 家庭住址 email
-- 注意点使用 英文() 表的名称 和 字段尽量使用''括起来
-- AUTO_INCREMENT自增
-- 所有语句后面加英文逗号,最后一个不用加
use school
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '名字',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMIT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
)ENGINE INNODB DEFAULT CHARSET=utf8;
格式:
CREATE TABLE [ IF NOT EXISTS] '表名'(
'字段名' 列类型 [属性] [索引] [注释],
'字段名' 列类型 [属性] [索引] [注释],
'字段名' 列类型 [属性] [索引] [注释],
......
'字段名' 列类型 [属性] [索引] [注释]
)[表的类型] [表的字符集] [注释];
常用命令
show create database school;--查看创建数据库的语句
show create table student;--查看创建表的语句
DESC student;--显示表的结构
/*
INNODB 默认使用
MYISAM 早些年使用
*/
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间大小 | 较小 | 较大 约为 MYISAM的两倍 |
经验 ( 适用场合 ) :
数据表的存储位置
MySQL数据表以文件方式存放在磁盘中
注意 :
设置数据表字符集
我们可为数据库,数据表,数据列设定不同的字符集,设定方法 :
修改
-- 修改表名
alter table 旧表 rename as 新表;
-- 增加表的字段
alter table 表名 add 字段名 字段列属性;
-- 修改表的字段(重命名 修改约束)
alter table 表名 modify 已有字段名 字段列属性; -- 修改约束
alter table 表名 change 原字段 新字段 字段列属性;-- 字段重命名
删除
-- 删除表的字段
alter table 表名 drop 需要删除的字段名
-- 删除表
DROP TABLE IF EXISTS exis 表名;
所有的创建删除操作 尽量加上判断 以免报错
注意
-- 年级表
CREATE TABLE `grade` (
`gradeid` int(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
`gradename` varchar(50) NOT NULL COMMENT '年级名',
PRIMARY KEY (`gradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 学生表的 gradeid 字段 要去引用 年级表的 gradeid
/*
定义外键key
给这个外键添加 约束 (执行引用)
*/
CREATE TABLE `student` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` varchar(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` varchar(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` varchar(2) NOT NULL DEFAULT '男' COMMENT '性别',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`gradeid` int(10) NOT NULL AUTO_INCREMENT COMMENT '学生的年级',
`address` varchar(100) DEFAULT NULL COMMENT '地址',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`),
KEY `FK_gradeid` (`gradeid`),
constraint `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 创建表的时候 没有外键关系
alter `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`);
--不想用 麻烦 !!!!!!!!~!!!
删除有外键关系的表的时候,必须要先删除引用别人的表(从表) 在删除被引用的表(主表)
最佳实践
数据库意义:数据存储 数据管理
DML语言:数据操作语言!
--插入语句(添加)
insert into 表名 (字段名1,字段名2,字段名3....) values('值1','值2','值3'...);
-- 由于主键自增 可以直接插入 不过必须插入全部字段
insert into 表名 values('值1','值2','值3'...);-- 不建议使用
-- 插入多个值
insert into 表名 (字段名1,字段名2,字段名3....) values('值1','值2','值3'),('值12','值22','值32')...;
注意事项:
update 修改谁 (条件) set 原来的值=新值
-- 修改student 表中学员的名字
update `student` set `name`='狂神' where id=1;
update `student` set `name`='狂神';-- 不指定条件的情况下 会改动 表中的所有该字段
-- 修改多个值 用英文逗号 隔开
-- 语法
update 表名 set colnum=value where 条件;
条件:where子句 运算符
操作符会返回布尔值
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=6 | false |
<>或!= | 不等于 | 5!=6或 5 <>6 | true |
> | 大于 | ||
< | 小于 | ||
>= | 大于等于 | ||
<= | 小于等于 | ||
between…and… | 在某个范围内 | [2,5] | |
and | && | ||
or | || |
注意
delete 命令
语法:delete from 表 [where 条件];
-- 删除数据 操作表 student
-- 删除指定数据
delete from `student` where id=1;
-- 删除全部数据
delete from `student`
TRUNCATE 命令
作用 :完全清空一个数据库表 表的结构 和约束 不会变
-- 清空表 student
TRUNCATE `student`;
delete && TRUNCATE 区别
--测试 delete && TRUNCATE 区别
CREATE TABLE `test` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`coll` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `test` (`coll`) values('1'),('2'),('3');
delete from `test`; --不会删除自增
TRUNCATE table `tesst`;-- 自增会归零
了解即可:DELETE 删除的问题 重启数据库, 现象
(Data Query LANGUAGE:数据查询语言)
SELECT 语法
SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
[left | right | inner join table_name2] -- 联合查询
[WHERE ...] -- 指定结果需满足的条件
[GROUP BY ...] -- 指定结果按照哪几个字段来分组
[HAVING] -- 过滤分组的记录必须满足的次要条件
[ORDER BY ...] -- 指定查询记录按一个或多个条件排序
[LIMIT {[offset,]row_count | row_countOFFSET offset}];
-- 指定查询的记录从哪条至哪条
测试用例!
-- 创建一个数据库
create database `school`;
-- 创建一张表
use `school`;
create table `grade`(
`GradeID` int(4) not null auto_increment comment '年级编号',
`GradeName` varchar(50) not null comment '年级名称',
primary key (`GradeID`)
)ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- 添加数据
insert into `grade` (`GradeID`, `GradeName`) values(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');
-- 创建reult 表
create table `result`(
`StudentNo` int(4) not null comment '学号',
`SubjectNo` int(4) not null comment '课程编号',
`ExamDate` DATETIME not null comment '考试日期',
`StudentResult` int(4) not null comment '考试成绩',
key `SubjectNo`(`SubjectNo`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 添加数据
insert into `result` (`StudentNo`,`SubjectNo`, `ExamDate`,`StudentResult`) values(1000,1,'2013-11-11 16:00:00',66);
-- 创建 student 表
create table `student`(
`StudentNo` int(4) not null comment '学号',
`LoginPwd` varchar(20) not null,
`StudentName` varchar(20) DEFAULT NULL comment '学生姓名',
`Sex` TINYINT(1) DEFAULT NULL comment '性别,取值0或1',
`GradeID` int(4) DEFAULT NULL comment '年级编号',
`Phone` varchar(50) not null comment '联系电话 允许为空',
`Address` varchar(255) not null comment '地址 允许为空',
`BornDate` DATETIME DEFAULT null comment '出生时间',
`Email` varchar(50) not null comment '邮箱账号 允许为空',
`IdentityCard` varchar(18) DEFAULT null comment '身份证',
primary key(`StudentNo`),
UNIQUE key `IdentityCard` (`IdentityCard`),
key `Email` (`Email`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 添加数据
insert into `student` (`StudentNo`,`LoginPwd`,`StudentName`,`Sex`, `GradeID`,`Phone` ,`Address`,`BornDate`, `Email`, `IdentityCard`) values(1001,'123456','李四',1,3,'18786506942','山海','1999-12-11 00:00:00','[email protected]','522428199912110812'),(1002,'123456','李林',0,3,'18786506942','西安','1999-02-11 00:00:00','[email protected]','522428199912110832'),(1003,'123456','韩立',1,3,'1878655542','北京','1999-02-11 00:00:00','[email protected]','412428199912110812');
-- subject 表
create table `subject`(
`SubjectNO` int(4) not null auto_increment comment '课程标号',
`SubjectName` varchar(50) DEFAULT NULL comment '课程名称',
`ClassHour` int(4) DEFAULT NULL comment '学时',
`GradeID` int(4) DEFAULT null comment '年级编号',
primary key (`SubjectNO`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 添加数据
insert into subject (`SubjectNO`, `SubjectName`,`ClassHour`,`GradeID`) values (1,'高等数学-1',110,1),(2,'高等数学-2',100,2),(3,'高等数学-3',130,3),(4,'高等数学-4',130,4),(5,'C语言-1',110,1),(6,'C语言-2',100,2),(7,'C语言-3',120,3),(8,'C语言-4',130,4);
查询所有的学生
语法:select 字段1… from 表 ;
select * from student;
-- 查询指定字段
SELECT `StudentNo`,`StudentName` FROM student;
别名 ,给结果起一个 名字 可以给字段取别名 也可以给表取 别名
SELECT `StudentNo` AS 学号,`StudentName` AS 名字 FROM student;
函数 Concat(a,b)
SELECT CONCAT('姓名:',StudentName) AS 新名字 FROM student;
有的时候,列的名字不是吧那么见名知意 我们可以起别名 AS 字段 as 别名 或者 表 as 表别名
去重 distinct
作用:去除Select 查询出来的结果中重复的数据 只显示一条
-- 查询有哪些同学参加了考试
SELECT * FROM result;-- 查询全部的成绩
-- 查询有哪些同学参加了考试
SELECT `StudentNo` FROM result;
-- 发现重复 去重
SELECT DISTINCT `StudentNo` FROM result;
数据库的列 (表达式)
-- 查看 mysql的版本
SELECT VERSION();
SELECT 100*3-1 AS 计算结果;--用来计算
SELECT @@auto_increment_increment; --查询自增的步长
-- 学员成绩 +1分 查看
SELECT `StudentNo`,`StudentResult` +1 AS '提分后' FROM result
****数据库中的表达式:文本值 列 NULL 函数 计算表达式 系统的变量…
select 表达式 form 表
作用:检索数据中符合条件的值
****搜索的条件由一个或者多个表达式组成 一般返回结果是一个 布尔值
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a&&b | 逻辑与 |
or || | a or b a ||b | 逻辑或 |
not ! | not a !a | 逻辑非 |
尽量使用英文字母
-- ===========WHERE ==============
SELECT studentNo,`StudentResult` FROM result;-- 列不区分大小写
-- 查询成绩在95~100之间的
SELECT studentNo,`StudentResult` FROM result WHERE StudentResult>=95 AND StudentResult <=100;
-- AND 用&&
SELECT studentNo,`StudentResult` FROM result WHERE StudentResult>=95 && StudentResult <=100;
-- 模糊查询
SELECT studentNo,`StudentResult` FROM result WHERE StudentResult BETWEEN 95 AND 100;
-- 除了 1000号学生之外的成绩 NOT
SELECT studentNo,`StudentResult` FROM result WHERE studentNo !=1000;
SELECT studentNo,`StudentResult` FROM result WHERE NOT studentNo =1000;
模糊查询
运算符 | 语法 | 描述 |
---|---|---|
IS NULL | a is null | 如果操作符结果为null则结果为true |
IS NOT NULL | a is not null | 如果操作符结果为null则结果为 false |
BETWEEN | a BETWEEN b and c | 如果a在 b和c之间,则结果为真 |
LIKE | a LIKE b | SQL 匹配 a如果匹配到b 则结果为真 |
in | a in(a1,a2,a3…) | 如果a在a1,a2,a3其中的某一个值中 则结果为真 |
模糊查询
-- 查询名字里面 韩 字开头de
--LIKE 结合%(0或多个字符) 和_(一个字符)
SELECT StudentNo,StudentName FROM student WHERE StudentName LIKE '韩%';-- 韩之后任意个字符
SELECT StudentNo,StudentName FROM student WHERE StudentName LIKE '韩_';-- 韩之后只有一个字
-- 查询名字中间有千字的同学
SELECT StudentNo,StudentName FROM student WHERE StudentName LIKE '%千%';-- 韩之后只有一个字
-- ==============================in==========================
-- 查询指定的学生 1001 1002 1003 号学生信息
SELECT StudentNo,StudentName FROM student WHERE StudentNo IN(1001,1002,1003);
-- 查询 在北京 的学生
SELECT StudentNo,StudentName,Address FROM student WHERE Address IN('北京');
-- =========== NULL NOT NULL=======================================================
-- 查询 Address 为null的同学
SELECT StudentNo,StudentName FROM student WHERE Address ='' OR Address IS NULL;
-- 查询有出生日期的学生 BornDate 不为空
SELECT StudentNo,StudentName,BornDate FROM student WHERE BornDate IS NOT NULL ;
JOIN 对比
!(mysqlnote.assets/image-20200804093124085.png)
-- 查询参加了考试的同学(学号 姓名 科目编号 分数)
SELECT * FROM student;
SELECT * FROM result;
/*
思路
1、分析需求 分析查询的字段来自哪些表 (连接查询)
2、确定使用哪种连接查询 ? 七种
确定交叉点(这两个表中 哪个数据是相同的)
判断的条件 :student.StudentNo =result.StudentNo
*/
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult
FROM student AS s
INNER JOIN result AS r WHERE s.StudentNo= r.StudentNo;
-- RIGHT JOIN
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult
FROM student AS s
RIGHT JOIN result AS r
ON s.StudentNo= r.StudentNo;
-- LEFT JOIN
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult
FROM student AS s
LEFT JOIN result AS r
ON s.StudentNo= r.StudentNo;
操作 | 描述 |
---|---|
INNNER JOIN | 如果表中至少有一个匹配,就返回匹配的值 |
LEFT JION | 会从左表中返回所有的值 即使右表中没有匹配 |
RGIGHT JION | 会从右表中返回所有的值 即使左表中没有匹配 |
-- 拓展 (查询了参加考试的同学信息 学号 学生 姓名 科目名 分数)
/*
思路
1、分析需求 ;分析查询的字段 来自哪些表 student result sunject (连接查询)
2、确定使用哪种连接查询 ? 七种
确定交叉点(这两个表中 哪个数据是相同的)
判断的条件:student.StudentNo=result.StudentNo
*/
SELECT s.StudentNo,StudentName,SubjectName,`StudentResult`
FROM student AS s
RIGHT JOIN result AS r
ON r.StudentNo=s.StudentNo
INNER JOIN `subject` sub
ON r.SubjectNo=sub.SubjectNo;
自连接
/*
自连接
数据表与自身进行连接
需求:从一个包含栏目ID , 栏目名称和父栏目ID的表中
查询父栏目名称和其他子栏目名称
*/
-- 创建一个表
CREATE TABLE `category` (
`categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',
`pid` INT(10) NOT NULL COMMENT '父id',
`categoryName` VARCHAR(50) NOT NULL COMMENT '主题名字',
PRIMARY KEY (`categoryid`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- 插入数据
INSERT INTO `category` (`categoryid`, `pid`, `categoryName`)
VALUES('2','1','信息技术'),
('3','1','软件开发'),
('4','3','数据库'),
('5','1','美术设计'),
('6','3','web开发'),
('7','5','ps技术'),
('8','2','办公信息');
自连接就是自己的表和自己的表连接 核心:一张表拆成两张一样的表
父类
categoryid | categoryName |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类表
pid | categoryid | categoryName |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
操作:查询父类对应的子类
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
-- 查询父子信息
SELECT a.categoryName AS '父栏目',b.categoryName AS '子栏目'
FROM `category` AS a,`category` AS b
WHERE a.categoryid=b.pid;
-- C查询学员所属的年级(学号 学生的姓名 年级名称)
SELECT `StudentNo`,`StudentName`,`GradeName`
FROM `student` AS s
INNER JOIN `grade` AS g
ON s.GradeID=g.GradeID;
-- 查询科目所属的年级(科目名称 年级名称)
SELECT SubjectName,GradeName
FROM grade as g
INNER JOIN `subject` AS sub
ON g.GradeID=sub.GradeID;
测试
/*============== 排序 ================
语法 : ORDER BY
ORDER BY 语句用于根据指定的列对结果集进行排序。
ORDER BY 语句默认按照ASC升序对记录进行排序。
如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。 */
-- 查询 数据库结构-1 的所有考试结果(学号 学生姓名 科目名称 成绩)
-- 按成绩降序排序
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY StudentResult DESC
/*============== 分页 ================
语法 : SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
好处 : (用户体验,网络传输,查询压力)
推导:
第一页 : limit 0,5
第二页 : limit 5,5
第三页 : limit 10,5
......
第N页 : limit (pageNo-1)*pageSzie,pageSzie
[pageNo:页码,pageSize:单页面显示条数]
*/
-- 每页显示5条数据
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY StudentResult DESC , studentno
LIMIT 0,5
-- 查询 JAVA第一学年 课程成绩前10名并且分数大于80的学生信息(学号,姓名,课程名,分数)
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='JAVA第一学年'
ORDER BY StudentResult DESC
LIMIT 0,10
/*============== 子查询 ================
什么是子查询?
在查询语句中的WHERE条件子句中,又嵌套了另一个查询语句
嵌套查询可由多个子查询组成,求解的方式是由里及外;
子查询返回的结果一般都是集合,故而建议使用IN关键字;
*/
-- 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列
-- 方法一:使用连接查询
SELECT studentno,r.subjectno,StudentResult
FROM result r
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC;
-- 方法二:使用子查询(执行顺序:由里及外)
SELECT studentno,subjectno,StudentResult
FROM result
WHERE subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '数据库结构-1'
)
ORDER BY studentresult DESC;
-- 查询课程为 高等数学-2 且分数不小于80分的学生的学号和姓名
-- 方法一:使用连接查询
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` sub
ON sub.`SubjectNo` = r.`SubjectNo`
WHERE subjectname = '高等数学-2' AND StudentResult>=80
-- 方法二:使用连接查询+子查询
-- 分数不小于80分的学生的学号和姓名
SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80
-- 在上面SQL基础上,添加需求:课程为 高等数学-2
SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '高等数学-2'
)
-- 方法三:使用子查询
-- 分步写简单sql语句,然后将其嵌套起来
SELECT studentno,studentname FROM student WHERE studentno IN(
SELECT studentno FROM result WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2'
)
)
-- 查询不同成绩的平均分 最高分 最低分
-- 核心:根据不同的课程分组
SELECT SubjectName ,AVG(StudentResult),MAX(StudentResult),MIN(StudentResult)
FROM result r
INNER JOIN `subject` sub
ON r.SubjectNo = sub.`SubjectNo`
GROUP BY r.SubjectNo;-- 通过什么字段来分组0
官网:https://dev.mysql.com/doc/refman/8.0/en/
花里胡哨
-- 数学运算
SELECT ABS(-8);-- 绝对值
SELECT CEILING(9.4);-- 向上取整
SELECT FLOOR(9.4);-- 向下取整
SELECT RAND();-- 返回一个0~1之间的一个随机数
SELECT SIGN(-56);-- 判断一个数的符号
-- 字符串函数
SELECT CHAR_LENGTH('即使再小的帆也能返航');-- 返回字符串长度
SELECT CONCAT('我','哎','你们');-- 拼接字符串
SELECT INSERT('我爱编程HelloWrold',2,2,'超级热爱')-- 查询替换 从某个位置 替换某个长度
SELECT LOWER('AAAAA');-- 转小写
SELECT UPPER('aaaaa');-- 转大写
SELECT INSTR('dfsgdfgdfgd','d');-- 查找某个字符串第一次出现的索引
时间日期
-- 时间日期
SELECT CURRENT_DATE();-- 获取当前日期
SELECT CURRENT_TIME();-- 获取当前时间
SELECT NOW();-- 获取 当前日期 时间
SELECT LOCALTIME(); -- 获取本地时间
函数名称 | 描述 |
---|---|
COUNT() | 计数 |
SUM() | 求和 |
AVG() | 平均值 |
MAX() | 最大值 |
MIN() | 最小值 |
-- 都能够统计表中的数据 COUNT()
SELECT COUNT(StudentName) FROM student;-- 统计人数 COUNT(字段) 会忽略 Null 值
SELECT COUNT(*) FROM student; -- COUNT(*) 不会忽略 Null 值
SELECT COUNT(1) FROM student; -- 不会忽略 Null 值
SELECT SUM(`StudentResult`) AS 总和 FROM result;-- 求和
SELECT AVG(`StudentResult`) AS 平均分 FROM result;-- 平均分
SELECT MAX(`StudentResult`) AS 最高分 FROM result;-- 最高得分
SELECT MIN(`StudentResult`) AS 最低分 FROM result;-- 最低得分
什么是MD5
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
-- ===================测试MD5 加密====================
CREATE TABLE `testmd5`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) not NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 明文密码
INSERT INTO testmd5
VALUES(1,'张三','123456'),
(2,'zhaoda','123456'),
(3,'lisi','123456'),
(4,'wangwu','123456');
-- 加密
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id=1;
UPDATE testmd5 SET pwd=MD5(pwd);-- 加密全部密码
-- 插入的时候加密
INSERT INTO testmd5
VALUES(6,'小明',MD5('123456'));
select * from testmd5;
-- 如何校验:将用户传递进来的密码 进行md5加密 然后对比加密后的值
SELECT *FROM testmd5 WHERE name='小明' AND pwd=MD5('123456');
要么都成功 要么都失败
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
将一组SQL 放在一个批次中去执行
INNODB支持
事务原则:ACID原则 原子性 一致性 隔离性 永久性 (脏读 幻读 不可重复读)
原子性(Atomic)
一致性(Consist)
隔离性(Isolated)
持久性(Durable)
隔离导致的一些问题
指一个事务读取了另外一个事务未提交的数据
在一个事务内读取表中的某行数据,多次读取结果不同。(这个不一定是错误 只是某些场合不对)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。。。。
事务的执行流程
执行事务
-- ==========事务====================
-- mysql默认开启事务自动提交的
SET autoccommit = 0;/*关闭*/
SET autoccommit = 1;/*开启(默认)*/
-- s手动处理事务
SET autoccommit = 0; -- 关闭自动提交
-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个开始的sql 都在同一个事务中
INSERT xx
INSERT yy
-- 提交 持久化(成功)
COMMIT
-- 回滚 回到原来的样子(失败)
ROLLBACK
-- 事务结束
SET autoccommit = 1;-- 开启自动提交
-- 了解
SAVEPOINT 保存点名称 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点
模拟场景
-- 转账
CREATE DATABASE `shop` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE shop;
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE = INNODB DEFAULT CHARSET=utf8;
INSERT into `account` (`name`,`money`) VALUES('A',2000.00),('B',10000);
-- 模拟转账
SET autocommit=0;-- 关闭自动提交
START TRANSACTION;-- 开启事务
UPDATE `account` SET money=money-500 WHERE name='A';-- A-500
UPDATE `account` SET money=money+500 WHERE name='B'; -- B+500
COMMIT;-- 提交事务
ROLLBACK; -- 回滚
SET autocommit = 1; -- 恢复默认值
MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构 。
提取句子主干 就可以得到索引的本质 :索引是数据结构
在一个表中 主键索引只能有一个 唯一索引可以有多个
基础语法
-- 索引的使用
-- 1、在创建表的时候给字段增加索引
-- 2、创建完毕后 增加索引
-- 显示所有索引信息
SHOW INDEX FROM `student`;
-- 增加一个索引 (索引名:列名)
ALTER TABLE school.`student` ADD FULLTEXT INDEX `StudentName`(`StudentName`);
-- EXPLAIN 分析SQL执行的状况
EXPLAIN SELECT * FROM student; -- 非全文索引
EXPLAIN SELECT * FROM student WHERE MATCH(StudentName) AGAINST('韩')
CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '' COMMENT '用户昵称',
`email` varchar(50) NOT NULL COMMENT '用户邮箱',
`phone` varchar(20) DEFAULT '' COMMENT '手机号',
`gender` tinyint(4) unsigned DEFAULT '0' COMMENT '性别(0:男;1:女)',
`password` varchar(100) NOT NULL COMMENT '密码',
`age` tinyint(4) DEFAULT '0' COMMENT '年龄',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表';
-- 插入100w条数据
DROP FUNCTION IF EXISTS mock_data;
DELIMITER $$ -- 写函数之前必须要写 标志
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i < num DO
-- 插入语句
INSERT INTO app_user(`name`, `email`, `phone`, `gender`, `password`, `age`)
VALUES(CONCAT('用户', i), '[email protected]', CONCAT('18', FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2),UUID(), FLOOR(RAND()*100));
SET i = i + 1;
END WHILE;
RETURN i;
END;
SELECT mock_data();
索引效率测试
无索引
SELECT * FROM app_user WHERE name = '用户9999'; -- 查看耗时
SELECT * FROM app_user WHERE name = '用户9999';
SELECT * FROM app_user WHERE name = '用户9999';
mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用户9999'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: app_user
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 992759
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
创建索引
CREATE INDEX idx_app_user_name ON app_user(name);
测试普通索引
mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用户9999'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: app_user
partitions: NULL
type: ref
possible_keys: idx_app_user_name
key: idx_app_user_name
key_len: 203
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)
mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)
mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)
索引的数据结构
-- 我们可以在创建上述索引的时候,为其指定索引类型,分两类
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)
-- 不同的存储引擎支持的索引类型也不一样
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;
使用SQLyog 创建用户,并授予权限演示
基本命令
/* 用户和权限管理 */ ------------------
用户信息表:mysql.user
-- 刷新权限
FLUSH PRIVILEGES
-- 增加用户 CREATE USER kuangshen IDENTIFIED BY '123456'
CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串)
- 必须拥有mysql数据库的全局CREATE USER权限,或拥有INSERT权限。
- 只能创建用户,不能赋予权限。
- 用户名,注意引号:如 'user_name'@'192.168.1.1'
- 密码也需引号,纯数字密码也要加引号
- 要在纯文本中指定密码,需忽略PASSWORD关键词。要把密码指定为由PASSWORD()函数返回的混编值,需包含关键字PASSWORD
-- 重命名用户 RENAME USER kuangshen TO kuangshen2
RENAME USER old_user TO new_user
-- 设置密码
SET PASSWORD = PASSWORD('密码') -- 为当前用户设置密码
SET PASSWORD FOR 用户名 = PASSWORD('密码') -- 为指定用户设置密码
-- 删除用户 DROP USER kuangshen2
DROP USER 用户名
-- 分配权限/添加用户
GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
- all privileges 表示所有权限
- *.* 表示所有库的所有表
- 库名.表名 表示某库下面的某表
-- 查看权限 SHOW GRANTS FOR root@localhost;
SHOW GRANTS FOR 用户名
-- 查看当前用户权限
SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();
-- 撤消权限
REVOKE 权限列表 ON 表名 FROM 用户名
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名 -- 撤销所有权限
权限解释
-- 权限列表
ALL [PRIVILEGES] -- 设置除GRANT OPTION之外的所有简单权限
ALTER -- 允许使用ALTER TABLE
ALTER ROUTINE -- 更改或取消已存储的子程序
CREATE -- 允许使用CREATE TABLE
CREATE ROUTINE -- 创建已存储的子程序
CREATE TEMPORARY TABLES -- 允许使用CREATE TEMPORARY TABLE
CREATE USER -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。
CREATE VIEW -- 允许使用CREATE VIEW
DELETE -- 允许使用DELETE
DROP -- 允许使用DROP TABLE
EXECUTE -- 允许用户运行已存储的子程序
FILE -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE
INDEX -- 允许使用CREATE INDEX和DROP INDEX
INSERT -- 允许使用INSERT
LOCK TABLES -- 允许对您拥有SELECT权限的表使用LOCK TABLES
PROCESS -- 允许使用SHOW FULL PROCESSLIST
REFERENCES -- 未被实施
RELOAD -- 允许使用FLUSH
REPLICATION CLIENT -- 允许用户询问从属服务器或主服务器的地址
REPLICATION SLAVE -- 用于复制型从属服务器(从主服务器中读取二进制日志事件)
SELECT -- 允许使用SELECT
SHOW DATABASES -- 显示所有数据库
SHOW VIEW -- 允许使用SHOW CREATE VIEW
SHUTDOWN -- 允许使用mysqladmin shutdown
SUPER -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。
UPDATE -- 允许使用UPDATE
USAGE -- “无权限”的同义词
GRANT OPTION -- 允许授予权限
/* 表维护 */
-- 分析和存储表的关键字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 检查一个或多个表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理数据文件的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
为什么要备份
MySQL数据库备份的方式
利用Navicat for MySQL这类的可视化工具导出( 花里胡哨 百度它不香吗)
使用命令行导出 mysqldump 命令行(小黑窗口)
-- 导出
1. 导出一张表 -- mysqldump -uroot -p123456 school student >D:/a.sql
mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
2. 导出多张表 -- mysqldump -uroot -p123456 school student result >D:/a.sql
mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)
3. 导出所有表 -- mysqldump -uroot -p123456 school >D:/a.sql
mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
4. 导出一个库 -- mysqldump -uroot -p123456 -B school >D:/a.sql
mysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)
可以-w携带备份条件
-- 导入
1. 在登录mysql的情况下:-- source D:/a.sql
source 备份文件
2. 在不登录的情况下
mysql -u用户名 -p密码 库名 < 备份文件
mysqldump客户端
作用 :
当数据库比较复杂的时候 我们就需要设计了
糟糕的数据库设计
良好的数据库设计:
软件开发中 关于数据库的设计
需求分析 :分析业务和需要处理的数据库需求
概要设计 设计相关的 E-R图
设计数据库步骤
收集信息
标识实体[Entity]
标识每个实体需要存储的详细信息[Attribute]
标识实体之间的关系[Relationship]
为什么需要数据规范化??
无法正常显示信息
丢失有效的信息
三大范式
**第一范式 (1st NF)**
第一范式的目标是确保每列的原子性,如果每列都是不可再分的最小数据单元,则满足第一范式
**第二范式(2nd NF)**
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
第二范式要求每个表只描述一件事情
**第三范式(3rd NF)**
如果一个关系满足第二范式,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式.
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
规范化和性能的关系
为满足某种商业目标 , 数据库性能比规范化数据库更重要
在数据规范化的同时 , 要综合考虑数据库的性能
通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间
通过在给定的表中插入计算列,以方便查询
驱动:声卡,显卡, 数据库
我们通过数据库驱动 和数据库打交道!!!
sun公司为了简化开发人员的(对数据库的统一操作)操作,提出来一个(java操作数据库)规范俗称 JDBC
这些规范的实现由具体的厂商去做
对于开发人员来说,只需要掌握JDBC接口的操作即可
java.sql
javax.sql
还需要导入数据库驱动包[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJLom8GM-1596981632139)(mysqlnote.assets/image-20200807183917832.png)]
Maven仓库中下载
官网下载(MAven 比较香 官网太难找)
2、创建一个测试数据库
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy;
CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
`email` VARCHAR(60),
birthday DATE
);
INSERT INTO users(id,`name`,`password`,`email`,birthday)
VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1980-12-04'),
(3,'wangwu','123456','[email protected]','1980-12-04');
3、导入数据库驱动
4、编写测试代码
package com.kuang.lesson01;
import java.sql.*;
//我的第一个JDBC程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1、加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");//固定写法,加载驱动
// 2、用户信息和 url
String url="jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT";
String username="root";
String password="123456";
// 3、连接成功 数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 4、执行SQL的对象 Statement 执行SQL 的对象
Statement statement = connection.createStatement();
// 5、执行SQL的对象执行SQL 可能存在结果 查看结果
String sql="select * from users";
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集
while(resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("name="+resultSet.getObject("name"));
System.out.println("password="+resultSet.getObject("password"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birthday="+resultSet.getObject("birthday"));
System.out.println("============================");
}
// 6、关闭数据库的连接 释放连接
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结
DriverManager
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver");//固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password);
//connection 代表数据库
//数据库设置自动提交
//事务提交
//事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit();
URL
String url="jdbc:mysql://localhost:3306/jdbcStudy?userUnicode= true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT";
//协议:端口号/数据库名?参数1&参数2.。。
//jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2.。。
//oracle --1521
//jdbc:oracle:thin:@localhost:1521:sid
Statement 执行SQL的对象 connection.prepareStatement()执行SQL的对象
String sql="select * from users";//编写SQL
statement.executeQuery();//查询 返回一个结果集
statement.execute();//执行任何SQL
statement.executeUpdate();//增删改SQL 都行 返回受影响的行数
ResultSet 查询的结果集 分装了所有的查询结果
获得指定的数据类型
resultSet.getObject();//在不知列类型的情况下使用
//如果知道列类型 就用相应的类型
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
.....
遍历,指针
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后
resultSet.next();//移动到下一个
释放资源
resultSet.close();
statement.close();
connection.close();//耗费资源 用完关掉
jdbc中的statement对象用于向数据库发送SQL语句,向完成对数据库增删改查,只要通过这个对象发送增删改查操作即可。
Statement对象的execteUpdate()方法,用于向数据库发送增删改查的语句,execteUpdate()执行完后将会返回一个整数(即对几条数据进行了操作)。
Statement.executeQuery()方法用于向数据库发送查询语句,executeQuery()方法将返回一个结果集ResultSet对象
CRUD操作-create
使用executeUpdate(String sql)方法完成数据库添加操作:
Statement st=com.createStatement();
String sql="insert into user(...) values(...)";
int num=st.executeUpDate(sql);
if(num>0){
System.out.print("插入成功");
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据库添加操作:
Statement st=com.createStatement();
String sql="delete from user where id=1";
int num=st.executeUpDate(sql);
if(num>0){
System.out.print("删除成功");
}
CRUD操作-update
使用executeUpdate(String sql)方法完成数据库更新加操作:
Statement st=com.createStatement();
String sql="update user set name='' where name=''";
int num=st.executeUpDate(sql);
if(num>0){
System.out.print("更新成功");
}
CRUD操作-read
使用executeUpdate(String sql)方法完成数据库读加操作:
Statement st=com.createStatement();
String sql="select *from user wher id=1";
ResultSet rs=st.executeUpdate(sql);
while(){
//根据获取的数据类型 分别调用rs的相应方法映射到java对象中
}
代码实现
1、提取工具类
db.properties
diver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
username=root
password=123456
package com.kuang.lesson02.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String diver=null;
private static String url=null;
private static String username=null;
private static String password=null;
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
diver = properties.getProperty("diver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
// 1、驱动只用加载一次
Class.forName(diver);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
// 释放连接资源
public static void release(Connection com, Statement st, ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} if (st!=null){
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} if (com!=null){
try {
com.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
2、编写增删改的方法
// 增删改 只需要改SQL语句
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn=JdbcUtils.getConnection();//获取数据库连接
st = conn.createStatement();//获得SQL的执行对象
String sql="INSERT INTO users(id,`name`,`password`,`email`,`birthday`) VALUES\n" +"(4,'kuanmgshen','123456','245456@','1990-02-01')";
int i= st.executeUpdate(sql);
if(i>0){
System.out.println("成功插入了"+i+"行数据");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
查询
//查询
public class TestRead {
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn= JdbcUtils.getConnection();//获取数据库连接
st = conn.createStatement();//获得SQL的执行对象
String sql="select * from users";
rs=st.executeQuery(sql);
while (rs.next()){
System.out.println("id="+rs.getInt("id"));
System.out.println("name="+rs.getString("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("==============================");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
SQL注入问题
SQL存在漏洞,会被攻击导致数据泄露!!!!!!!!
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
PrePareStatementd可以防止sql注入效率更高
1、新增
package com.kuang.lession03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestInsert {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用占位符代替参数
String sql="INSERT INTO users(id,`name`,`password`,`email`,`birthday`) VALUES(?,?,?,?,?)";
st= conn.prepareStatement(sql);//预编译sql
// 手动给参数复制
st.setInt(1,4);
st.setString(2,"kuangshen");
st.setString(3,"123456");
st.setString(4,"[email protected]");
// 注意点 sql.Date 数据库
// util.Date java new Date().getTime())获得时间戳
st.setDate(5,new java.sql.Date(new Date().getTime()));
// 执行
int i=st.executeUpdate();
if (i>0){
System.out.println("插入成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
2、删除
package com.kuang.lession03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
public class TestDelete {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用占位符代替参数
String sql= "delete from users where id=?";
st= conn.prepareStatement(sql);//预编译sql
// 手动给参数复制
st.setInt(1,4);
// 执行
int i=st.executeUpdate();
if (i>0){
System.out.println("删除成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
3、更新
package com.kuang.lession03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用占位符代替参数
String sql= "update users set name =? where id=?";
st= conn.prepareStatement(sql);//预编译sql
// 手动给参数复制
st.setString(1,"kuang");
st.setInt(2,4);
// 执行
int i=st.executeUpdate();
if (i>0){
System.out.println("更新成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
4、查询
package com.kuang.lession03;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestRead {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
ResultSet rs=null;
try {
conn = JdbcUtils.getConnection();
// 区别
// 使用占位符代替参数
String sql= "select * from users where id=?";
st= conn.prepareStatement(sql);//预编译sql
// 手动给参数复制
st.setObject(1,1);
// 执行
rs=st.executeQuery();
while (rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
5、防止SQL注入
package com.kuang.lesson02;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.*;
public class SQL注入 {
public static void main(String[] args) {
// login("lisi","123456");
login("''or 1=1","123456");
}
//登录业务
public static void login(String username,String password){
Connection conn=null;
// PreparedStatement 防止注入的本质 就是把传递进来的参数当做字符
// 加入其中出现转义字符 比如说 ‘’就被转义了
PreparedStatement st=null;
ResultSet rs=null;
try {
conn= JdbcUtils.getConnection();//获取数据库连接
String sql="select * from users where `name`=? and `password`=?";
st=conn.prepareStatement(sql);
st.setString(1,username);
st.setString(2,password);
rs=st.executeQuery();
while (rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getObject("password"));
System.out.println("===================");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
1、连接数据
2、连接成功后可以选择数据库
要么都成功 要么都失败!!!!
ACID原则
要么全部完成要么都不完成
总数不变
多个进程互不干扰
一旦提交不可逆 持久化到数据库
隔离性的问题
一个事务读取了另外一个没有提交的事务
不可重复读
在同一个事务内,重复读取表中的数据,表数据发生了改变
幻读(虚读)
在一个事务内,读取到了别人插入的数据,导致前后读取的数据不一样。
代码实现
1、开启事务 : conn.setAutoCommit(false);
2、一组业务执行完毕 提交事务
3、可以在catch语句中显示的定义 回滚语句 但默认失败 自动回滚
数据库
create table account(
id int primary key auto_increment,
name varchar(40),
money float
);
insert into account(name, money) VALUES ('A',1000);
insert into account(name, money) VALUES ('B',1000);
insert into account(name, money) VALUES ('C',1000);
业务逻辑代码
package com.kuang.lession04;
import com.kuang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction1 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
ResultSet rs=null;
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交 自动开启事务
conn.setAutoCommit(false);
String sql1="update account set money=money-100 where name='A'";
st=conn.prepareStatement(sql1);
st.executeUpdate();
// int x=1/0;//报错
String sql2="update account set money=money+100 where name='B'";
st=conn.prepareStatement(sql2);
st.executeUpdate();
// 业务完毕 提交事务
conn.commit();
System.out.println("成功");
} catch (SQLException throwables) {
try {//如果失败就回滚
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
数据库连接-----执行完毕—释放
连接—释放 十分浪费系统资源
池化技术 准备一些预先的资源,过来就连接 预先准备好的
最小连接数 依情况而定(常用:100 最小连接数:100)
最大连接数: 业务做高承载上限
排队等候
等待超时
编写连接池 实现一个接口 DataSource
开放数据源实现
DBCP
c3p0
Druid:阿里巴巴
使用了这些数据库连接池之后 我们在项目开发中就不需要编写连接数据库的代码
DBCP
需要用到的jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g2lMrRXe-1596981632142)(mysqlnote.assets/image-20200808215429045.png)]
C3P0
需要导入的jar包
结论
无论使用什么数据源 本质还是一样的 DataSource接口不会变