1、初始mysql
javaEE:企业级java开发, 开发Web
前端 (页面:展示 ,数据!)
后台 连接点:连接数据库 JDBC,连接前端(控制,控制视图跳转,和给前端传递数据)
数据库 (存数据:早期:Txt,Excel,word!)
只会写代码,学好数据库,基本混饭吃!
学好操作系统(自己开发mysql),数据结构与算法(调高mysql的效率)! 不错的程序员~
离散数学,数字电路,体系结构,编译原理 +实战经验 高级程序员~优秀程序员!
1.1、为什么学习数据库
1、岗位需求
2、现在的世界,大数据时代~得数据者得天下!
3、被迫需求:存数据 去IOE
4、数据库是所有软件体系当中最核心的存在 DBA
1.2、什么是数据库
数据库(DB DateBase)
概念:数据仓库,软件,安装在操作系统(Windows,Linux,mac、....)之上!SQL,可以存储大量的数据!500万以下!
作用:存储数据,管理数据
1.3、数据库分类
关系型数据库:(SQL)
行、列(狭义)
-
MySQL、Oracl、SQL Server、DB2、SQLlite
-
通过表与表之间、行和列之间的关系进行数据的存储, 比如学员信息表 ,考勤表....
非关系型数据库:(NO SQL) Not Only
{key:value}(狭义)
-
Redis、MongDB
-
非关系型数据库,对象存储,通过对象自身的属性来决定!
DBMS(数据库管理系统)
-
数据库的管理软件,科学有效的管理我们的数据,维护和获取数据!
-
MySQL,数据库管理系统
1.4、MySQL简介
MySQL是一个关系型数据库管理系统
前身:由瑞典 MySQL AB 公司开发
今世:属于 Oracle 旗下产品
MySQL是最好的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性
体积小、速度快、总体拥有成本低 招人的成本下降
一般中小型和大型网站的开发都选择 MySQL作为网站数据库
安装建议:
1.尽量不要使用exe,注册表(卸载不干净!)
2.尽可能的使用压缩包安装~
1.5、进入数据库
命令行连接
net start mysql -- 启动数据库 mysql -u root -p 密码 -- 连接数据库 --所有的数据库都是 ; 结尾 show databases; -- 展示所有的数据库 use mysqstu; -- 切换数据库 use 数据库名 show tables; -- 展示当前数据库下的所有表 describe student; -- 展示数据库当中的student表的信息 create database DB -- 创建一个数据库
2、操作做数据库
操作数据库>操作数据库中的表>操作数据库中表的数据
2.1、操作数据库
1、创建数据库
CREATE DATABASE [IF NOT EXISTS] westos;
2、删除数据库
drop DATABASE [ IF EXISTS] ls;
3、使用数据库
-- 如果关键字为特殊字符需要哦使用 ` ` USE westos;
4、查看数据库
SHOW DATABASES ;
2.2、数据库的列类型
数值
-
tinyint 十分小的数据 8bit
-
smallint 较小的数据 16bit
-
mediumint 中等大小的数据 24bit
-
int 标准的整数 32bit
-
bigint 较大的数据 64bit
-
float 浮点数 64bit
-
double 浮点数 64bit
-
decimal 字符串形式的浮点数 金融计算的时候,一般使用decimal
字符串
-
char 字符串的固定长度 0~255
-
varchar 可变字符串 0~65535
-
tinytext 微文本 2^32-1
-
text 文本串 2^64-1
时间日期
-
data YYYY-MM-DD,日期格式
-
time HH:mm:ss , 时间格式
-
datatime YYYY-MM-DD HH:mm:ss 最常用的时间格式、
-
timestamp 时间戳 ,1970.1.1到现在的毫秒数! 比较常用 (需要在拿到后在java中用format()转换)
-
year 年份表示
null
-
没有值,未知
-
注意,不要使用NULL进行运算,结果为NULL
2.3、数据库的字段属性(重点)
Unsigned:
-
无符号的整数
-
声明了该列不能声明为负数
zerofill:
-
0填充
-
不足的位数,使用0来填充,int(3) , 5.....005
自增:
-
通常理解为自增,自动在上一条记录的基础上+1(默认)
-
通常用来设计唯一的主键~index,必须是整数类型
-
可以自定义的设计主键自增的起始值和步长
非空:NULL not null
-
假设设置为not null ,如果不给他赋值,就会报错!
-
NULL,如果不填写值,默认就是null
默认:
-
设置默认的值
-
sex,
拓展:
2.4、数据库表创建(重点)
--注意点,使用英文的(),表的名字和字段 尽量使用 `` 括起来 --AUTO_INCREMENT 自增 --字符串使用单括号 --所有的额语句后面加,(英语的) ,最后一个不用加 -- PRIMARY KEY 主键,一般一个表只有一个唯一的主键 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 COMMENT '家庭住址', `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
格式
CREATE TABLE IF NOT EXISTS `表名` ( `字段名` 数据类型 [属性][索引] [注释], `字段名` 数据类型 [属性][索引] [注释], ... `字段名` 数据类型 [属性][索引] [注释], PRIMARY KEY (`主键列`), FOREIGN KEY (`外键列`) REFERENCES `相关表名` (`相关列`), ... ) [表类型][字符集设置][注释]
常用命令
SHOW CREATE DATABASE blog; ---查看创建数据库的语句 SHOW CREATE TABLE teacher; ---查看teacher数据库表的定义语句 DESC teacher; --显示表的结构
2.5、数据库的类型
--关于数据库引擎 /* ** INNODB 默认使用~ MYISAM 早期使用 */
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间的大小 | 较小 | 较大,约为2倍 |
常规使用操作:
MYISAM 节约空间,速度较快
INNODB 安全性高,事务的处理,多表多用户操作
在物理空间存在的位置
所有的数据文件都存在data目录下,一个文件对应一个数据库
本质还是文件对的存储!
Mysql引擎在物理文件上的区别
-
INNODB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
-
MYISAM对应文件
-
*.frm 表结构的定义文件
-
*.MYD 数据文件(data)
-
*.MYI 索引文件(index)
-
设置数据库表的字符集编码
CHARSER=uft8
不设置的话,会是mysql默认的字符集编码~(不支持中文!)
MySQL的默认编码是Latin1,不支持中文
在my.ini中配置默认的编码(不建议使用)
character-set-serve=utf8
2.6、修改删除表
修改
# 修改表名 ALTER TABLE 旧表名 RENAME AS 新表名 ALTER TABLE tb_user RENAME AS test_user; #增加表的字段名 ALTER TABLE 表名 ADD 字段名 列属性; ALTER TABLE test_user ADD sex VARCHAR(2); #修改表的字段 (重命名 修改约束!) ALTER TABLE test_user MODIFY age VARCHAR(11); #修改约束 ALTER TABLE test_user CHANGE age age1 INT(1); # 删除表的字段 ALTER TABLE test_user DROP sex;
删除
# 删除表 DROP TABLE if EXISTS test_user;
所有的创建和删除操作尽量加上判断,以免报错!
3.MySQL数据管理
3.1、外键(了解)
# 创建年级表 CREATE TABLE `grade` ( `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id', `gradename` VARCHAR(50) NOT NULL COMMENT '年级名称', PRIMARY KEY (`gradeid`) ); # 学生表的gradeid字段要求引用grade表中的gradeid # 定义外键key # 给这个外键添加约束(执行应用) references 引用 CREATE TABLE IF NOT EXISTS `student` ( `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT 'studentID', `name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名', `pwd` VARCHAR(30) NOT NULL DEFAULT '123456' COMMENT '密码', `sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别', `birthday` DATETIME DEFAULT NULL COMMENT '出生日期', `gradeid` INT(10) NOT NULL COMMENT '年级id', `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`) ); # 创建表的时候没有外键关系 ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`); #ALTER TABLE 表名 ADD CONSTRAINT 约束名 FOREIGN KEY (作为外键的列) REFERENCES `引用的表` (`该表的那个字段`);
以上操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰,这里了解即可~)
最佳实践
-
数据库就是单纯的表,只用来存储数据,只有行(数据)和列(字段)
-
我们想要使用多张表的数据,想要使用外键(用程序去实现)
3.2、DML语言 (全部记住)
数据库的意义:数据存储、数据管理
DML语言:数据操作语言
-
insert
-
update
-
delete
3.3、添加
insert
# 插入语句 # inserte into `表名`([字段名1,字段名2,字段名3]) values('值1','值2','值3'),('值1','值2','值3'),('值1','值2','值3'); INSERT INTO `grade` (`gradename`) VALUES ('大四'); # 虽然主键是自增的但是我们不可以省略当我们没写表的字段时(因为不写字段时,他们会一一匹配 INSERT INTO `grade` VALUES ('大三'); # 插入多个字段 INSERT INTO `grade` (`gradename`) VALUES ('研究生一'), ('大一'); INSERT INTO `student` (`name`, `pwd`, `sex`, `birthday`) VALUES ('张三', '000000', '男', '2003-12-26'); INSERT INTO `student` (`name`, `pwd`, `sex`, `birthday`) VALUES ('萍', '000000', '女', '2003-12-26'), ('李四', '000000', '男', '2002-12-26'), ('何', '000000', '女', '2003-12-26'), ('罗', '000000', '男', '2002-12-26');
语法:inserte into 表名
([字段名1,字段名2,字段名3]) values('值1','值2','值3'),('值1','值2','值3'),('值1','值2','值3');
注意事项:
1.字段和字段之间使用 英文逗号隔开
2.字段是可以省略的,但是后面的值必须要一一对应,不能少
3.可以同时插入多条数据,values后面的值,需要使用 逗号隔开即可
3.4、修改
update 修改谁(条件) set 原来的的值=新值
# 修改数据 # 修改学生姓名,带了条件 UPDATE `student` SET `name`='王耀' WHERE id=3; # 不指定条件的情况下,会改动所有表!(拒绝使用) UPDATE `student` SET `name`='王耀' ; # 修改多个属性,用逗号隔开 UPDATE `student` SET `name`='何',`email`='2549615161@qq.com' WHERE id =5; # 语法 # UPDATE `表名` SET `colnum_name`=vlue,[`colnum_name`=vlue,`colnum_name`=vlue,.....] WHERE [条件];
条件:where 子句 运算符 id等于某个值,大于某个值,在某个区间内修改
操作符会返回布尔值
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 相等 | 5=6 | false |
<>或!= | 不相等 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
BETWEEN...AND... | 在某个范围内 | [2,5] | |
AND | 我和你&& | 5>1and1>3 | false |
OR | 我或你|| | 5>1or 1>3 | true |
# 通过多个定位条件定位数据 UPDATE `student` SET `name`='王耀' WHERE id=3 AND sex='男';
语法:UPDATE 表名
SET colnum_name
=vlue,[colnum_name
=vlue,colnum_name
=vlue,.....] WHERE [条件];
注意事项:
-
colnum_name是数据库的列,尽量带上
-
条件,筛选的条件,如果没有指定,则会修改所有的列
-
value,是一个具体的值,也可以是一个变量
-
多个设置的属性之间,使用英文逗号隔开
UPDATE `student` SET `birthday`=current_time WHERE id =5;
3.5、删除
delete 命令
语法:delete from 表名 [where 条件]
# 删除数据( 避免这样写,会全部删除) DELETE FROM `student` ; # 删除指定数据 DELETE FROM `student` WHERE id=1;
TRUNCAT命令
# 清空student表 TRUNCATE `student`
DELETE 与TRUNCATE 的区别
-
相同点:都能删除数据,都不会删除表结构
-
不同:
-
TRUNCATE 重新设置 自增列(AUTO_INCREMENT) 计数器会归零(类似格式化)
-
TRUNCATE 不会影响事务
-
了解即可:DELETE删除的问题,重启数据库,现象
-
InnoDB 自增列会从1开始(存在内存当中的.断电即失)
-
MyISAM 继续从上一个自增量开始(存在文件中的,不会丢失)
4.DQL查询数据(最重要)
4.1 DQL
(Data Query LANGUAGE:数据查询语言)
-
所有的查询操作都是用它,select
-
简单的查询,复杂的查询他都做
-
数据中最核心的语言,最重要的语句
-
使用频率最高的语句
4.2、指定查询字段
# 查询所有的成绩 SELECT * FROM result; # 查询所有的字段 SELECT `studentno` ,`studentname` FROM student; # 取别名 SELECT `studentno` AS 学生id,`studentname` AS 学生姓名 FROM student AS st; # 函数 concat(a,b) SELECT concat('姓名:',studentname) As 字符串拼接 FROM student;
语法:SELECT 字段1,.... FROM 表
SELECT 字段1,.... FROM 表
去重 distinct
作用:去掉SELECT 查询结果的中的重复数据 ,重复的数据只显示一条~
# 查询那些同学参加了考试,成绩 SELECT * FROM result; #查询所有的考生的所有的考试成绩 SELECT studentno FROM result; #查询哪些同学参加了考试 SELECT DISTINCT studentno FROM result; #发现重复数据,去重
数据库的列(表达式)
SELECT version(); #查询系统版本(函数) SELECT 100*3 AS '计算结果'; #用来计算(表达式) SELECT @@auto_increment_increment ; #查询自增步长(变量) # 学员考试成绩+1分查看 SELECT `studentno`,`studentresult`+1 FROM result;
数据库中的表达式:文本值,列,null,函数,计算表达式,系统变量........
select 表达式 from 表
Select完整的语法
4.3、where条件子句
作用:检索数据中符合条件的值
搜索条件由一个或者多个表达式组成!结果 布尔值
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | A and b A && B | |
or || | A or b A || B | |
not ! | not A ! A |
尽量用英文
模糊查询 比较运算符
运算符 | 语法· | 描述 |
---|---|---|
IS NULL | A IS NULL | 如果操作符为NULL,结果为真 |
IS NOT NULL | A IS NOT NULL | 如果操作不为NULL,结果为真 |
BETWEEN AND | C BETWEEN A AND B | 若c在a和b之间,则结果为真 |
LIKE | A LIKE B | SQL匹配,如果A匹配B成功,则结果为真 |
IN | A IN (a1,a2,a3) | 如果A 在a1,a2,a3....值中的某一个,结果为真 |
# ============== 模糊查询 ============== # in(具体的一个或者多个值) # 查询1001,1002,1003号学员 SELECT `studentno`,`studentno` FROM `student` WHERE studentno in (1001,1003,1002); # 查询在北京的学生 SELECT `studentno`, `studentname` FROM student WHERE `address` IN ('上海浦东');
4.4、联表查询
Join
on是连表前的条件,where是连表后的过滤
操作 | 描述 |
---|---|
Inner join | 如果表中至少由一个匹配(就连表条件能够匹配),就返回行 |
left join | 以左表作为主表,右表为从表,所以会返回左表中的所有值,然后将左表条件与右表条件一一匹配 |
right join | 以右表作为主表,左表为从表,所以会返回右表中的所有值,然后将右表条件与左表条件一一匹配 |
# ============= 联表查询 ========== # 查询参加了考试的同学(学号,姓名,科目编号,分数) /** 思路 1.分析需求,分析查询的字段来自那些表,(连接查询) 2.确定使用那种连接查询? 7种 确定交叉点(这两个表中那个数据是相同的) 判断的条件:学生中的studentNo = 成绩表 studentNo */ # join (连接的表) on (判断的条件) (连接查询) # where (等值查询) SELECT s.studentno, studentname, subjectno, studentresult FROM student s INNER JOIN result r ON s.studentno = r.studentno; # Right join SELECT s.studentno, studentname, subjectno, studentresult FROM student s RIGHT JOIN result r ON s.studentno = r.studentno; # Left join SELECT s.studentno, studentname, subjectno, studentresult FROM student s LEFT JOIN result r ON s.studentno = r.studentno; # 查询缺考的同学 SELECT s.studentno, studentname, subjectno, studentresult FROM student s LEFT JOIN result r ON s.studentno = r.studentno WHERE studentresult IS NULL; # 思考题 (查询了参加考试的同学的信息:学号,学生姓名,科目名,分数) /** 思路 1.分析需求,分析查询的字段来自那些表,student、result、subject(连接查询) 2.确定使用那种连接查询? 7种 确定交叉点(这两个表中那个数据是相同的) 判断的条件:学生中的studentNo = 成绩表 studentNo 成绩表 subjectNo =学科表 subjectNo */ SELECT s.studentno,studentname,subjectname,studentresult FROM student s RIGHT JOIN result r ON s.studentno = r.studentno INNER JOIN subject sub ON r.subjectno=sub.subjectno; # 我要查询哪些数据 select .... # 从那几个表中from 表 XXX Join 连接的表 on 交叉条件 # 假设存在一种多张表查询,慢慢来,先查询两种表,然后再慢慢增加
自连接
自己的表和自己的表连接,核心:一张表拆分为两张一样的表即可
父类
顶级id就是pid=1因为1的值唯一
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 a, category b WHERE b.pid = a.categoryid;
# 查询学员所属的年级(学号,学生的姓名,年级名称) SELECT studentno, studentname, gradename FROM student s LEFT JOIN grade g ON s.gradeid = g.gradeid; SELECT studentno, studentname, gradename FROM student s INNER JOIN grade g ON s.gradeid = g.gradeid; # 查询科目所属的年级 SELECT gradename FROM subject s LEFT JOIN grade g ON s.gradeid = g.gradeid; # 查询参加了 数据库管理 考试的同学信息(学号,姓名,科目编号,分数) SELECT s.studentno, studentname, sub.subjectname, r.studentresult FROM student s INNER JOIN result r ON s.studentno = r.studentno INNER JOIN subject sub ON sub.subjectno = r.subjectno WHERE subjectname = '数据库管理';
4.5、分页和排序
排序
# ======== 分页 limit 和排序 order by========= # 排序 :升序 ASC ,降序 DESC # ORDER BY 通过那个字段排序,怎么排 # 查询的结果的根据 成绩排序 排序 SELECT s.studentno, studentname, sub.subjectname, r.studentresult FROM student s INNER JOIN result r ON s.studentno = r.studentno INNER JOIN subject sub ON sub.subjectno = r.subjectno WHERE subjectname = '数据库管理' ORDER BY studentresult DESC ;
分页查询
# 100w条数据 # 为什么要分页? # 缓解数据库压力,给人的体验更好! # 分页,每页只显示五条数据 # 语法:limit 起始值,页面的大小 # limit 0,5 1~5 # limit 5,5 6~11 SELECT s.studentno, studentname, sub.subjectname, r.studentresult FROM student s INNER JOIN result r ON s.studentno = r.studentno INNER JOIN subject sub ON sub.subjectno = r.subjectno WHERE subjectname = '数据库管理' ORDER BY studentresult DESC LIMIT 5,5; # 第一页 limit 0,5 # 第二页 limit 5,5 # 第n页 limit (n-1)*pageSize, # 【pageSize:页面大小】 # 【(n-1)*pageSize:起始值】 # 【n:当前页】 # 【数据总数/页面大小=总页数】
4.6、子查询
where (这个值是计算出来的)
本质:在where语句中嵌套一个子查询语句
where(selcet *from)
一般能够用联表查询的也可以用子查询进行嵌套
# ============== where ============ # 1、查询 数据库管理 的所有考试结果(学号、科目编号、成绩),降序排列 # 方式一:使用连接查询 SELECT r.`studentno`, sub.`subjectno`, `studentresult` FROM result r INNER JOIN subject sub ON r.subjectno = sub.subjectno WHERE subjectname = '数据库管理' ORDER BY studentresult DESC ; # 方式二:使用子查询() # 查询所有的 数据库管理 的学生学号 SELECT `subjectno` FROM subject WHERE subjectname='数据库管理'; SELECT `studentno`, `subjectno`, `studentresult` FROM result; # 方式三 其实就是自己干了数据库查询的"4"的这一步 SELECT `studentno`, `subjectno`, `studentresult` FROM result WHERE subjectno=4;
5、MySQL函数
5.1、常用函数
5.2、聚合函数以及分组过滤
过滤聚合函数只能使用having
# =================== 聚合函数 =============== # 都能够统计,表中的数据(想要查询一个表中有多少个记录,就会使用这个count()) SELECT COUNT(studentname) FROM student;#count(指定列),会忽略所有的null的值 SELECT COUNT(*) FROM student;#count(*),不会忽略所有的null的值,本质 计算行数 SELECT COUNT(1) FROM student; #count(1),不会忽略所有的null的值,本质 计算行数 # 查询不同课程的平均分,最高分,最低分 # 核心:(根据不同的课程分组) SELECT subjectname, AVG(studentresult), MAX(studentresult), MIN(studentresult) FROM result r INNER JOIN subject sub ON r.subjectno = sub.subjectno GROUP BY r.subjectno HAVING AVG(studentresult)>80;
5.3、数据库级别的MD5加密(扩展)
什么是MD5?
主要增强算法复杂度和不可逆性。
MD5不可逆,具体的值的MD5是一样的
MD5破解网站的原理,背后有一个字典,MD5加密后的值 加密前的值
# ======== 测试MD5 加密 =========== CREATE TABLE `testmd5`( `id` INT(4) NOT NULL, `name` VARCHAR(20) NOT NULL, `pwd` VARCHAR(50) NOT NULL, PRIMARY KEY (`id`) ); # 明文密码 INSERT INTO testmd5 VALUES (1,'zs','123456'),(2,'ls','123456'),(3,'wu','1234567'); # 加密 UPDATE testmd5 SET pwd=MD5(pwd) WHERE id =1; UPDATE testmd5 SET pwd=MD5(pwd); #加密全部的密码 # 插入的时候进行加密 INSERT INTO testmd5 VALUES (4,'lc',MD5('123456')); #如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值 SELECT * FROM testmd5 WHERE `name` ='lc' and `pwd`=md5('123456');
5.4、Select小结
6、事务
6.1、什么事务
要么成功,要么都成功~
1、SQL执行 A给B转账 A 1000 ——> 200 B 200
2、SQL执行 B收到A的转账 A 800 ——> B 400
————
将一组SQL放到一个批次中去执行
事务原则:ACID原则 原子性、一致性、隔离性、持久性 (脏读、幻读)
参考博客链接:数据库ACID四大特性到底为了啥,一文带你看通透-CSDN博客
原子性(Atomicity)
要么都成功,要么都失败!
一致性(Consistency)
事务前后的数据完整性要保证, 比如 转账前后,两个用户账户余额加起来都是一样的
隔离性(Isolation)
通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
持久性(Durability) ----事务提交
事务一旦提交则不可逆,被持久化到数据库中!即使系统崩溃,修改的数据也不会丢失!
隔离所导致的一些问题
脏读:
指一个事务读取了另一个事务未提交的数据
不可重复读:
在一个事务内读取表中的某一行数据,多次读取的结果不一样;(这个不一定是错误,只是某些场合不对)
幻读:
是指在一个事务内读取到了别的事务新插入的数据,导致前后读取不一致。
执行事务
# ================ 事务 =============== # mysql 是默认开启事务自动提交的 SET AUTOCOMMIT = 0 ;/* 关闭 */ SET AUTOCOMMIT = 1 ; /* 开启(默认的)*/ # 手动处理事务 # 事务开启 START TRANSACTION; # 标记一个事务的开始,从这个之后的SQL都在同一个事务内 /* sql语句 */ # 提交: 持久化(成功!) COMMIT ; # 回滚: 回到原来的样子(失败!) ROLLBACK ; # 事务结束 SET AUTOCOMMIT = 1; #开启自动提交 # 了解 SAVEPOINT 保存点名; #设置一个事务的保存点 ROLLBACK TO SAVEPOINT 保存点名; #回滚到保存点 RELEASE SAVEPOINT 保存点名; #撤销保存点
模拟
# 转账 CREATE DATABASE shop; USE shop; CREATE TABLE `account` ( `id` INT(3) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) NOT NULL, `money` DECIMAL(9, 2) NOT NULL DEFAULT (0), PRIMARY KEY (`id`) ); INSERT INTO account (`name`, `money`) VALUES ('A', '20000.00'), ('B', '50000.00'); #模拟转账:事务 SET AUTOCOMMIT = 0; #关闭自动提交 START TRANSACTION; #开启一个事务(一组事务) UPDATE account SET money=money-100 WHERE `name`='A'; #A转账B 500元 UPDATE account SET money=money+100 WHERE `name`='B'; #B收到A 500元 COMMIT ; #提交事务,就被持久化了! ROLLBACK ; # 回滚 SET AUTOCOMMIT = 1;
7、索引
MySQL官方对索引的定义为:缩影(index)是帮助MySQL高效获取数据的数据结构。普通 0.5s 索引:0.01s
提取句子主干,就可以得到所有的本质:索引是数据结构。
主要用于解决并发问题
7.1、索引的分类
在一个表中,主键索引只能有一个,唯一索引可以有多个
-
主键索引(PRIMARY KEY)
-
唯一的标识,主键不可以重复,只能有一个列作为主键。
-
-
唯一索引(UNIQUE KEY)
-
避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
-
-
常规索引(KEY/INDEX)
-
默认的
-
-
全文索引(FullText)
-
在特定的数据库引擎中才有
-
快速定位数据
-
参考博客链接:【MySQL优化】——看懂explain_mysql优化——看懂explain-CSDN博客
CodingLabs - MySQL索引背后的数据结构及算法原理
基础语法:
# 索引的使用 # 1、创建表的时候给字段增加索引 # 2、创建完毕后,增加索引 # 显示所有的索引信息 SHOW INDEX FROM account; # 增加一个索引(索引名) 列名 ALTER TABLE account add FULLTEXT INDEX `name`(`name`); #EXPLAIN 分析sql的执行的状况 EXPLAIN SELECT * FROM school.student; #非全文索引 EXPLAIN SELECT * FROM school.student WHERE MATCH(studentname) AGAINST('刘')
7.2、测试索引
use school; CREATE TABLE `app_user` ( `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(64) DEFAULT '' COMMENT '用户名称', `email` VARCHAR(32) NOT NULL COMMENT '用户邮箱', `phone` VARCHAR(32) DEFAULT '' COMMENT '手机号', `gender` TINYINT(4) UNSIGNED DEFAULT 0 COMMENT '性别(0:男,1:女)', `password` VARCHAR(32) NOT NULL COMMENT '密码', `age` TINYINT(4) DEFAULT 0 COMMENT '年龄', `create_time` DATETIME DEFAULT current_timestamp, `update_time` TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'; # 插入百万数据 DELIMITER $$ #写函数之前必须要写 CREATE FUNCTION mock_data1() RETURNS INT DETERMINISTIC SQL SECURITY INVOKER 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),'2549615161@qq.com',floor(concat('177',rand()*(99999999-10000000)+10000000)),rand()*2,uuid(),rand()*100); SET i=i+1; END WHILE ; RETURN i; END; COMMIT ; # id_表名_字段名 # create index 索引名 on 表(字段) # 创建索引 CREATE INDEX id_app_user_name ON app_user(`name`); SELECT * FROM app_user WHERE `name`='用户19999'; # 0.001ms EXPLAIN SELECT * FROM app_user WHERE `name`='用户19999';
索引在小数据量的时候,用处不大,但是大数据量的时候,区别十分明显~
7.3、索引原则
-
索引不是越多越好
-
不要将索引加到经常变动的字段
-
小数据量的表不需要添加索引
-
索引一般加在常用来查询的字段上
索引的数据结构
hash类型索引
Btree:InnoDB的默认数据结构~
阅读; CodingLabs - MySQL索引背后的数据结构及算法原理
8、数据库的权限管理和备份
8.1、用户管理
#创建用户 CREATE USER 用户名 IDENTIFIED BY '密码' CREATE USER wangyao IDENTIFIED BY '123456'; # 修改密码(修改当前用户密码) SET PASSWORD=PASSWORD('123456'); # 修改密码(修改指定用户密码) SET PASSWORD FOR wangyao=PASSWORD ('123456'); # 修改用户名 RENAME USER 原来名字 TO 新的名字 RENAME USER wangyao TO NewWangYao; # 用户授权 ALL PRIVILEGES (全部的权限),库.表 (*.* 所有的库.所有的表) # ALL PRIVILEGES 除了给别人授权外(root的权限只差这一个),其他的权限他都有 GRANT ALL PRIVILEGES ON *.* TO wangyao; # 查询权限 SHOW GRANTS FOR wangyao; #查看指定用户的权限 SHOW GRANTS FOR root@localhost; #查看root用户需要加上地址 #撤销权限REVOKE 哪些权限,在哪个库撤销,FROM 给谁撤销 REVOKE ALL PRIVILEGES ON *.* FROM wangyao; # 删除用户 DROP USER wangyao;
8.2、MySQL备份
为什么要备份;
-
保证重要的数据不丢失
-
数据转移
MySQL数据库备份的方式
-
直接拷贝物理文件
-
在可视化工具导出数据
-
使用命令行导出mysqldump 命令
#mysqldump -h主机 -u用户名 -p密码 数据库 表名 > 物理磁盘地址 mysqldump -hlocalhost -uroot -p123456 school student >d:a.sql #mysqldump -h主机 -u用户名 -p密码 数据库 表名1 表名2 > 物理磁盘地址 mysqldump -hlocalhost -uroot -p123456 school student student1>d:a.sql #mysqldump -h主机 -u用户名 -p密码 数据库 > 物理磁盘地址 mysqldump -hlocalhost -uroot -p123456 school >d:a.sql #导入 #登陆的情况下,切换到指定的数据库 #source 备份文件 source d:/a.sql mysql -u用户名 -p密码 库名<备份文件
假设你要备份数据库,防止数据丢失。
把数据库给别人,sql文件给别人即可!
9、规范数据库设计
当数据库比较复杂的时候,我们就需要设计数据库
糟糕的数据库设计:
-
数据库冗余,浪费空间
-
数据库插入和删除都会比较麻烦,异常[屏蔽使用物理外键]
良好的数据库设计:
-
节省内存空间
-
保证数据库的完整性
-
方便我们的系统开发
软件开发中,关于数据库的设计
-
分析需求:分析业务和需要处理的数据库的需求
-
概要设计:设计关系图E-R图
设计数据库的步骤:(个人博客)
-
收集信息,分析需求
-
用户表(用户登陆注销,用户的个人信息,写博客,创建分类)
-
分类表(文章分类,谁创建的)
-
文章表(文章的信息)
-
友链表
-
9.2、三大范式
10、数据库的归约,三大范式
10、JDBC(重点)
10.1、数据库驱动
驱动:显卡、数据库
我们的程序会通过数据库驱动,和数据库打交道~
10.2、JDBC
SUN公司为了简化开发人员的(对数据库的统一)操作, 提供了一个(java操作数据库的)规范 ,俗称JDBC
这些规范的具体实现有数据库厂商去做!
对于开发人员只需要掌握JDBC的接口!
java.sql
javax.sql (java自带)
还需要导入一个数据库驱动包 mysql-connector-java-xxxx.jar
10.3、第一个JDBC程序
创建测试数据库
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, 'zhansan', '123456', 'zs@sina.com', '1980-12-04'), (2, 'lisi', '123456', 'lisi@sina.com', '1981-12-04'), (3, 'wangwu', '123456', 'wangwu@sina.com', '1979-12-04');
1、创建一个Maven项目
2、在pom.xml中添加mysql驱动
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>
3、编写 测试代码
2、在pom.xml中添加mysql驱动
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>
3、编写 测试代码
步骤总结:
1、加载驱动
2、连接数据库DriverManager
3、获取执行sql的对象Statement
4、获取返回的结果集
5、释放连接
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.getAutoCommit(); connection.commit(); connection.rollback();
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true"; //mysql -- 默认端口 3306 //jdbc:mysql://主机地址:端口号/数据库名称?参数1&参数2&参数3&参数4 //oracle --默认端口 1521 //jdbc:ocracle:thin:@主机地址:端口 :sid
Statement执行SQL的对象 Prestatement执行SQL的对象
String Sql = "select * from work"; Statement statement = connection.createStatement(sql); PreparedStatement updateStatement = connection.prepareStatement(updateSql); statement.executeQuery();//查询操作返回ResultSet statement.execute();//执行如何SQL statement.executeUpdate();//更新、插入、删除,都使用这个,返回一个受影响的行数
ResultSet查询的结果集:封装了所有的查询结果
遍历,指针
释放内存
10.4、Statemnet对象
数据库配置文件
diver: "com.mysql.cj.jdbc.Driver"
url: "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true"
username: "root"
password: "xxxxxxx"
jdbc基本配置
package com.lc.utils;
import org.yaml.snakeyaml.Yaml;
import java.io.InputStream;
import java.sql.*;
import java.util.Map;
import java.util.Objects;
/**
* 功能:
* 作者:lc
* 日期:2024/5/5 19:37
*/
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.yml");
Yaml yaml = new Yaml();
Map<String, Objects> data = yaml.load(in);
diver = String.valueOf(data.get("diver")); // 使用 String.valueOf() 转换对象为字符串
url = String.valueOf(data.get("url"));
username = String.valueOf(data.get("username"));
password = String.valueOf(data.get("password"));
// 加载驱动
System.out.println(diver);
Class.forName(diver);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
// 建立数据库连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
// 释放连接
public static void release(Connection connection, Statement statement, ResultSet rs) {
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement !=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
实例:
package com.lc.test;
import com.lc.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 功能:
* 作者:lc
* 日期:2024/5/5 20:23
*/
public class Test1 {
public static void main(String[] args) throws SQLException {
Connection cnn = null;
Statement st = null;
ResultSet rs=null;
try {
cnn=JdbcUtils.getConnection();
st=cnn.createStatement();
String sql="INSERT INTO teacher(`tno`, `tname`,`tage`,tsex) VALUES ('520', 'hlp','18','女')";
int i=st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(cnn,st, rs);
}
}
}
SQL注入
sql存在漏洞,会被攻击导致数据泄露
本质就是条件拼接
10.5、PreparedStatement对象
案例:
package com.lc.test;
import com.lc.utils.JdbcUtils;
import java.sql.*;
/**
* 功能:
* 作者:lc
* 日期:2024/5/5 21:29
*/
public class Test2 {
public static void main(String[] args) {
Connection cnn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try{
cnn = JdbcUtils.getConnection();
String sql="INSERT INTO teacher(`tno`, `tname`,`tage`,tsex) VALUES (?,?,?,?)";
pst= cnn.prepareStatement(sql);//预编译sql,先写sql,然后不执行
//手动参数赋值
pst.setInt(1,125);
pst.setString(2,"hlp&lc");
pst.setInt(3,99);
pst.setString(4,"女");
int i = pst.executeUpdate();
if (i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(cnn,pst,rs);
}
}
}
10.6、事务
-------------后面还有点连接池的内容,后面有时间后在补上----------------
-------------------喜欢的可以点一个关注,谢谢!------------------------------