MySQL基础笔记整理
1.1 为什么学习数据库
-
岗位需求
-
大数据时代
-
被迫需求:存数据
-
数据库是所有软件体系中最核心的存在DBA
1.2 什么是数据库
数据库(DB,Database)
概念:数据仓库,软件,安装在操作系统(window,linux,mac...)之上
作用:存储数据,,管理数据
1.3 数据库分类
关系型数据库:(SQL)
-
MySQL,Oracal,SqlServer,DB2,SQLlite
-
通过表和表之间,行列之间的关系进行数据库存储,学员信息表,考勤表,...
非关系型数据库:(NOSQL)Not Only
-
Redis,MongDB
-
非关系型数据库,对象存储,通过对象的自身的属性来决定
DBMS(数据库管理系统)
-
数据库的管理软件,科学的管理我们的数据,维护和获取数据
-
Mysql是一个关系型数据库管理系统
-
前世:瑞典MySQL AB公司
-
今生:Oracle 旗下产品
-
MYSQL是最好的RDBMS(关系数据库管理系统)应用软件之一
-
开源的数据库软件,体积小,速度快,总体拥有成本低,
创建数据库
新建连接
新建数据库
创建表
查看表
命令行连接数据库
C:\Users\16225>mysql -uroot -p123456 --连接数据库
mysql>
update mysq1.user set authenticati on_string=password('123456') where user= 'root and Host ='localhost'; --修改用户密码
flush privileges; --刷新权限
----------------------------------
--所有软件都必须使用;结尾
mysql> show databases; --查看数据库
mysql> use school --使用数据库
mysql> show tables; --查看数据库中表
mysql> describe student; --查看表结构
mysql> create database westos;--创建数据库
Query OK, 1 row affected (0.00 sec)
exit --推出连接
-- <注释>
数据库xxx语言
DDL :数据库定义语言
DML:数据库操作语言
DQL:数据库查询语言
DCL:数据库控制语言
操作数据库
-
创建数据库
CREATE DATABASE IF NOT EXISTS west
-
使用数据库
USE test
-
删除数据库
DROP DATABASE IF EXISTS westos
-
查看数据库
SHOW DATABASES
数据库的列类型
数值
-
tinyint :十分小 一个字节
-
smallint: 两个字节
-
mediumint:三个字节
-
int :四个字节(常用的)
-
bigint :八个字节
-
float:四个字节(浮点数)
-
double:八个字节(浮点数)
-
decimal:字符串形式的浮点数(金融计算时候)
字符串
-
char :固定大小的字节0~255
-
varchar:可变字符串0~65535常用的变量
-
tintext:微型文本 2^8-1
-
text 文本串 2^16-1保存文本
时间日期
-
date :日期YYYY-MM-DD
-
time:时间 HH:mm:ss
-
datetime:YYYY-MM-DD HH:mm:ss
-
timestamp:时间戳,1970.1.1到现在的毫秒数! 也比较常用
-
year:年份表示
null
-
没有值,未知
-
注意,不要使用NULL进行运算,结果为NULL
数据库的字段属性(重点)
Unsigned:
-
无符号的整数
-
声明了该列,不能声明为负数
zerofill:
-
0填充的
-
不足的位数,使用0来填充 int(3),5----005
自增:
-
通常理解为自增,自动在上一条记录的基础上+1(默认加一,可以修改)
-
通常用来设计唯一的主键~index,必须是整数类型
-
可以自定义主键自增的起步初始值和步长
非空:Null not null
-
假设设置为not null ,如果不给赋值,就会报错
-
null, 如果不填写值,默认就是null!
默认
-
设置默认的值!
-
sex,默认设置为男,如果不指定该列的值,则会有默认值
拓展
/*每一个表,都必须存在以下五个字段!未来做项目用的,表示每一个记录存在的意义
id:主键
`version`:乐观锁
is_delete:伪删除
gmt_create:创建时间
gmt_update:修改时间
*/
用命令创建数据库中的表
--命令行创建表
/*AUTO_INCREMENT:自动递增
表名和字段名都得加``,防止字段名和表名是关键字
PRIMARY KEY(`id`):一般只有一个主键
括号都为英文括号
DEFAULT :默认字段
COMMENT:注释
*/
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(3) NOT NULL AUTO_INCREMENT COMMENT'学号',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT'姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT'密码',
`age` INT(3) NOT NULL DEFAULT '18' COMMENT'年龄',
`sex` VARCHAR(3) NOT NULL DEFAULT '男' COMMENT'性别',
`birthday` DATETIME DEFAULT NULL COMMENT'出生日期',
`email` VARCHAR(20) DEFAULT NULL COMMENT'邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
--创建表公式
CREATE TABLE [IF NOT EXISTS] `student`(
字段名 数据类型 [属性] [索引] [注释],
字段名 数据类型 [属性] [索引] [注释],
字段名 数据类型 [属性] [索引] [注释],
......
字段名 数据类型 [属性] [索引] [注释]
)ENGINE=INNODB DEFAULT CHARSET=utf8
常用命令
SHOW CREATE DATABASE school; -- 查看创建数据库的语句
--CREATE DATABASE `school` /*!40100 DEFAULT CHARACTER SET utf8 */
SHOW CREATE TABLE student; -- 查看数据库中的表的语句
DESC student; -- 显示表的结构
MYISAM和InnoDB区别
| INNODB | MYISAM | |
|---|---|---|
| 事务操作 | 支持 | 不支持 |
| 数据行锁定 | 支持 | 不支持 |
| 外键约束 | 支持 | 不支持 |
| 全文索引 | 不支持 | 支持 |
| 表空间的大小 | 较大(约为MYISAM的两倍) | 较小 |
常规使用的操作:
-
MYISAM:节约空间,速度较快
-
INNOODB:安全性高,事务的处理,多表多用户操作
--关于数据库引擎
/*
INNODB :默认使用
MyISAM :早些年使用
*/
在物理空间存在的位置
所有的数据库文件都存在data文件执下
本质还是文件的存储
-
INNODB在数据库中只有一个
设置数据库的字符集编码
charset=utf8
不设置的话,会是mysql默认的字符集编码Latin1(不支持中文)
修改删除表
修改表
-- 删除表 DROP TABLE [IF EXISTS] 表名;
DROP TABLE IF EXISTS teacher;
-- 增加表的字段:ALTER TABLE 表名 ADD 添加的字段名 数据类型 [属性]
ALTER TABLE student1 ADD psw VARCHAR(20) NOT NULL DEFAULT '123456';
-- 修改表名:ALTER TABLE 表名 RENAME AS 改后的表名;
ALTER TABLE 表名 RENAME AS 新表名;
ALTER TABLE 表名 MODIFY `字段` 数据类型; -- 修改约束
ALTER TABLE 表名 CHANGE `旧字段名` `新字段名` 数据类型;-- 修改字段名称
-- 删除表的字段:ALTER TABLE 表名 DROP 字段;
ALTER TABLE student1 DROP pwd;
删除表
-- 删除表 DROP TABLE 表名;
DROP TABLE teacher;
-
所有的创建和删除操作尽量加上判断,以免报错
注意点:
-
`` 字段名 使用这个包裹
-
注释/* */
-
sql关键字大小写不敏感,建议写小写
-
所有符号都写英文
-
MySQL数据管理
外键(了解即可)
DML语言(全部记住)
数据库意义:存储数据,管理数据
DML:数据操作语言
-
insert
-
update
-
delete
添加
insert
--添加多条数据语法:INSERT INTO 表名 ([字段名1],[字段名2],[字段名3],) VALUE(),();
INSERT INTO `student1` (`name1`,`age`,`sex`) VALUE('张三','18','男'),('李四','18','女');
--添加一条数据语法:INSERT INTO 表名 ([字段名1],[字段名2],[字段名3],) VALUE();
INSERT INTO `student1` (`name1`,`age`,`sex`) VALUE('李四','18','女');
--不写字段时候,必须与表中的列一一对应
INSERT INTO `student1`
VALUE('80','张三','18','男','2020-11-15 06:30:30','122517@qq.com','789654'),('100','李四','18','女','2020-11-15 15:40:59','122517@qq.com','789654');
-
注意事项:
-
符号必须都是英文符号,不能有中文符号;
-
字段名必须与value中的值一 一对应;
-
字段名可以省略不写,但是value中的值必须与表中列的字段一 一对应;
-
多个字段的时候,value用逗号隔开VALUE('张三','18','男'),('李四','18','女');
修改
update 修改谁 (条件) set 字段=赋予新值
UPDATE `student1` SET `name1`='王麻子' WHERE id=5;--修改id=5的name字段的值
UPDATE `student1` SET `name1`='王麻子';--不指定条件的话,把所有的name都改
UPDATE `student1` SET `name1`='张三',age=68,psw='240162' WHERE id=6;--修改多个字段用逗号隔开即可
UPDATE `student1` SET `name1`='chenlei',age=68,psw='240162' WHERE id BETWEEN 2 AND 4;-- 改变区间的值
条件:where子句 运算符 id等于某个值,大于某个值,在某个区间内修改....
操作符会返回boolean值
| 操作符 | 含义 | 范围 | 结果 |
|---|---|---|---|
| = | 等于 | 5=6 | false |
| !=或者<> | 不等于 | 5<>6 | true |
| > | 大于 | ||
| < | 小于 | ||
| >= | 大于等于 | ||
| <= | 小于等于 | ||
| between...and | 在某个范围内 | [2,5] | |
| and | 我和你&& | 5>1and1>5 | false |
| or | 我或你|| | 5>1and1>5 | true |
语法:update 表名 set colnum_name=value,[colnum_name=value].... where条件
注意:
-
colum_name是数据库的列,尽量带上``
-
条件,筛选的条件,如果没有指定,则会修改所有的列
-
value,是一个具体的值,也可以是一个变量
-
多个设置的属性之间,使用英文逗号隔开
删除
delete命令
语法:delete from 表明 [where 条件]
DELETE FROM student1;-- 删除表中所有数据
DELETE FROM student1 WHERE id=101;-- 添加条件得删除
TRUNCATE命令
作用:完全清空一个数据库表,表的结构和索引约束不会变
TRUNCATE student1;-- 删除表中所有数据
delete 和truncate的区别
相同点:都能删除数据,都不会删除表结构
不同点:
-
turncate 重新设置自增列 计数器会归零
-
truncate 不会影响事务
DELETE FROM student1; --不会影响自增
TRUNCATE student1; --自增会归零
了解:delete删除问题,重启数据库,现象
-
Innodb: 自增列会重1开始(存在内存当中,关机即失)
-
MyISAM:继续上一个自增量开始(存在文件中,不会丢失)
DQL查询数据(最重点)
(Database Query Language:数据库查询语言)
-
所有的查询操作都用它,Select
-
简单的查询。复杂的查询都用它
-
数据库最核心的语言,最重要的语言
-
使用频率最高的语言
select语法
SELECT [ALLI DISTINCT]
{* 1 table.* | [table.field1[as alias1][,table. field2[as alias2]][....]]}
FROM table_ name [as table_ _alias]
[left | right 1 inner join table_ name2] -- 联合查询
[WHERE ...] -- 指定结果需满足的条件
[GROUP BY ...1] -- 指定结果按照哪几个字段来分组
[HAVING] -- 过滤分组的记录必须满足的次要条件
[ORDER BY ...] --指定查询记录按一个或多个条件排序
[LIMIT {[offset,]row_ count | row_ countOFFSET offset}];
--指定查询的记录从哪条至哪条
SELECT * FROM student1;-- 查询表中所有的数据
SELECT `name1`,`age` FROM student1;-- 查询表中特有的字段
-- 把字段改为自己想要的字段,表和字段都可以改,用as连接
SELECT `name1` AS 姓名, `sex` AS 性别 ,`age` AS 年龄 FROM student1 AS s;
-- 函数CONCAT('年龄:',`age`)
SELECT CONCAT('年龄:',`age`) AS 新年龄 FROM student1;
去重distant
作用:去除select查询出来的结果中重复的数据
SELECT DISTINCT age FROM student1; -- 去掉字段中重复的数据,只显示一条
数据库的列(表达式)
SELECT VERSION(); --查询系统版本 SELECT 100*2-1 AS 计算结果:; SELECT `name1`,`age`+2 AS 新年龄 FROM student1;-- 全体年龄加一
数据库中的表达式: 文本值,列,NUll,函数,计算表达式,系统变量
select 表达式 from 表
where条件子句
作用:检索数据中符合条件的值
搜索的条件由一个或多个表达式组成!结果为布尔值
逻辑运算符
| 运算符 | 语法 | 描述 |
|---|---|---|
| and && | a and b a&&b | 逻辑与,两个都为真,结果为真 |
| or | a or b a||b | 逻辑或,其中一个为真,则结果为真 |
| not | not a !a | 逻辑非,真为假,假为真! |
尽量使用英文字母
-- 查询年龄和姓名,并且年龄在20-50之间, SELECT `name1`,`age` FROM student1 WHERE age BETWEEN 20 AND 50; -- 查询年龄和姓名,并且年龄在20-50之间, SELECT `name1`,`age` FROM student1 WHERE age BETWEEN 20 AND 50; -- 查询年龄大于20,并且小于50的名字 SELECT `name1`,`age` FROM student1 WHERE age>=20 AND age<=50; -- 查询年龄不等于18岁的名字 SELECT `name1` AS 姓名,`age` AS 年龄 FROM student1 AS 学生表 WHERE NOT age=18;
模糊查询
模糊查询(比较运算符)
| 运算符 | 语法 | 描述 |
|---|---|---|
| is null | a is null | 如果操作符为null,结果为真 |
| is not null | a is not null | 如果操作符不为null,结果为真 |
| between | a bewteen b an c | 若a在b和c之间 结果为真 |
| like | a like b | sql匹配,如果a匹配b,则结果为真 |
| in | a in (a1,a2,a3......) | 假设a在a1,或者a2....其中摸一个值中,结果为真 |
-- ============= like模糊查询(like只能在like中使用) ============= -- 查询姓陈的 SELECT `name1`,`age` FROM student1 WHERE `name1` LIKE '陈%'; -- 查询姓陈的,知道具体名字为几个字 SELECT `name1`,`age` FROM student1 WHERE `name1` LIKE '陈_'; -- 查询姓名中带有'佳'字 SELECT `name1` FROM student1 WHERE `name1` LIKE '%佳%'; -- ==============in(是一个准确的值,不能用%) =================== SELECT `name1`,`age` FROM student1 WHERE `age` IN (18,66); -- ==============is null not is null=========================== -- 查询 email 为空的学生名字 SELECT `name1`,`email` FROM student1 WHERE `email` IS NULL; SELECT `name1`,`email` FROM student1 WHERE `email` IS NULL OR `email`=''; -- 空 SELECT `name1`,`email` FROM student1 WHERE `email`=''; -- 空字符串 -- 查询 email 不为空的学生名字 SELECT `name1`,`email` FROM student1 WHERE `email` IS NOT NULL; -- ===================between ======================== -- 查询年龄在18-30之间的名字 SELECT `name1`,`age` FROM student1 WHERE age BETWEEN 18 AND 30;
联表查询join
| 操作 | 描述 |
|---|---|
| inner join | 如果表中至少有一个匹配,就返回行 |
| left join | 会从左表中返回所有的值,即使右表中没有匹配 |
| right join | 会从右表中返回所有的值,即使左表中没有匹配 |
`test`-- ====================联表查询======================== /*思路: 1.分析需求,分析查询的字段来自哪些表(连接查询) 2.确定使用哪种连接查询?七种, 确定交叉点(这两个表中哪个数据是相同的) 判断条件:学生表中的id=成绩表 id */ -- 查询参加了考试的同学(学号id,姓名,科目编号,分数) -- join (连接的表) on (判断条件) 连接查询 -- where 等值查询 -- =================inner================ SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult` FROM student AS s INNER JOIN result AS r ON s.`StudentNo`=r.`StudentNo`; -- ==================left=============== SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult` FROM student AS s LEFT JOIN result AS r ON s.`StudentNo`=r.`StudentNo`; -- ==================right=============== SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult` FROM student AS s RIGHT JOIN result AS r ON s.`StudentNo`=r.`StudentNo`;`result``student``result``student` -- ===========查询缺考学生================= SELECT s.`StudentNo`,`StudentName`,`SubjectNo`,`StudentResult` FROM student AS s RIGHT JOIN result AS r ON s.`StudentNo`=r.`StudentNo` WHERE StudentResult IS NULL
自连接以及联表查询
自连接:自己的表和自己的表连接,核心:一张表拆为两张一样的表即可
分析:
父类:
| categoryid | categoryName |
|---|---|
| 2 | 信息技术 |
| 3 | 软件开发 |
| 5 | 美术设计 |
子类:
| pid | categoryid | categoryName |
|---|---|---|
| 2 | 8 | 办公信息 |
| 5 | 7 | ps技术 |
| 3 | 6 | web开发 |
| 3 | 4 | 数据库 |
父类对应子类的关系
| 信息技术 | 办公信息 |
| 软件开发 | 数据库 |
| 美术设计 | ps技术 |
| 软件开发 | web开发 |
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','办公信息');
-- =============自连接=====================
SELECT c.categoryName AS '父类', b.categoryName AS '子类'
FROM category AS c , category AS b
WHERE c.categoryid=b.pid
分页和排序
分页limit
-- ================分页======================= SELECT s.`StudentNo`,`StudentName`,`StudentResult` FROM student AS s INNER JOIN result AS r WHERE `StudentResult` IS NOT NULL ORDER BY `StudentResult` DESC LIMIT 0,5; -- ============================================ /*分页语法: 第一页: LIMIT 0,5; (1-1)*5 第二页: LIMIT 5,10; (2-1)*5 第三页: LIMIT 10,15; (3-1)*5 第n页: LIMIT ?,?; (n-1)*pageSize 【pageSize:页面大小】 【(n-1)*pageSize:起始值】 【n:当前页】 【数据总数/页面大小=总页数】 数据总数/页面大小 除下不等于0页面数加一 */
排序order by 升序asc 降序 desc
-- =============升序============================= SELECT s.`StudentNo`,`StudentName`,`StudentResult` FROM student AS s INNER JOIN result AS r WHERE `StudentResult` IS NOT NULL ORDER BY `StudentResult` ASC ; -- ==============降序======================== SELECT s.`StudentNo`,`StudentName`,`StudentResult` FROM student AS s INNER JOIN result AS r WHERE `StudentResult` IS NOT NULL ORDER BY `StudentResult` DESC ;
语法:limit(查询起始的下标,pageSize)
子查询和嵌套查询
常用的函数
时间和日期函数
-- ==========常用的函数=============== SELECT VERSION();-- 获取版本 SELECT SYSDATE(NOW()); -- SELECT NOW(); -- 获取当前时间日期 SELECT CURRENT_DATE(); -- 获取当前日期 SELECT USER(); -- 当前用户 SELECT SYSDATE(); -- 获取系统时间 SELECT LOCALTIME(); -- 获取本地时间
聚合函数
| 函数名称 | 描述 |
|---|---|
| count() | 计数 |
| sum() | 求和 |
| avg() | 求平均数 |
| max() | 最大值 |
| min() | 最小值 |
-- ================聚合函数============== -- 三种都能进行计数,COUNT(`StudentName`)计算具体列的数 -- 不会把NUll进行计数, SELECT COUNT(`StudentName`) FROM student; SELECT COUNT(`LoginPwd`) FROM student; -- 不会忽略null值, 本质 计算行数 SELECT COUNT(*) FROM student; -- 不会忽略所有的NULL值, 本质 计算行数 SELECT COUNT(1) FROM student; SELECT SUM(`StudentResult`) AS '总和' FROM result; SELECT AVG(`StudentResult`) AS '平均数' FROM result; SELECT MAX(`StudentResult`) AS '最大值' FROM result; SELECT MIN(`StudentResult`) AS '最小值' FROM result;
分组和过滤
SELECT SubjectName, AVG (StudentResult) AS平均分, MAX (StudentResult) ,MIN (StudentResult) FROM result r INNER JOIN subject sub ON r.SubjectNoi = sub.SubjectNo GROUP BY r.SubjectNo --通过什么字段来分组 HAVING 平均分>80
数据库加密级别的MD5加密
MD5不可逆,具体的值得MD5是一样的
MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值
-- ===========MD5加密===========================
-- 插入数据时加密
INSERT INTO `student` (`StudentNo`,`LoginPwd`,`StudentName`) VALUE('1005',MD5('123456'),'陈磊');
-- 把明文密码加为密文密码
UPDATE `student` SET LoginPwd=MD5(LoginPwd) WHERE StudentNo=1000;
-- 把全部明文密码改为密文
UPDATE `student` SET LoginPwd=MD5(LoginPwd);
Select 总结
事务
什么是事务?
要么都成功,要么都失败
一一一一一一一一
1.SQL执行 A给B转账
2.SQL执行 B收到A的钱
一一一一一一一一
将一组SQL放在一个批次中去执行~
事务原则 ACID原则 :原子性,一致性,隔离性,持久性 ()脏读,幻读.....
原子性(A):
要么都成功,要么都失败
一致性(C):
事务前后的数据完整性要保持一致,1000
隔离性(I):
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启事务,不能被其他事务的操作数据所干扰,事务之间要相互隔离
持久性(D):
事务一旦提交则不可逆,被持久到数据库中
隔离所导致的一些问题
脏读:指一个事务读取了另一个事务未提交的数据
不可重复度:在一个事务内读取表中的某一 行数据,多次读取结果不同。 (这个不一-定是错误,只是某些场合不对)
幻读:是指在一一个事务内读取到了别的事务插入的数据,导致前后读取不一-致。
执行事务
-
MySQL是默认开启事务自动提交的
-- MYSQL 是默认开启事务自动提交的 SET autocommit = 0 -- 关闭 SET autocommit = 1 -- 开启,默认开启 -- 手动处理事务 SET autocommit = 0 -- 关闭自动提交 -- 事务开启 START TRANSACTION -- 标记一个事务的开始,从这个之后的 sql 都在同一个事务内 INSERT xx INSERT xx -- 提交:持久化(成功) COMMIT -- 回滚:回到原来的样子(失败) ROLLBACK -- 事务结束 SET autocommit = 1 -- 开启自动提交 -- 了解 SAVEPOINT 保存点 -- 设置一个事务的保存点 ROLLBACK TO SAVEPOINT 保存点 -- 回滚到保存点 RELEASE SAVEPOINT 保存点 -- 撤销保存点
模拟场景
CREATE DATABASE IF NOT EXISTS shop CHARSET utf8 COLLATE utf8_general_ci; -- 创建数据库
CREATE TABLE IF NOT EXISTS `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.00);
SELECT * FROM account;
SET autocommit = 0; -- 关闭事务自动提交
START TRANSACTION; -- 开启事务
-- 一组事务
UPDATE `account` SET money=money-500 WHERE `name`='A';
UPDATE `account` SET money=money+500 WHERE `name`='B';
COMMIT ; -- 提交事务(事务一旦被提交,就被持久化了,不能回滚了)
ROLLBACK -- 回滚
SET autocommit = 1; -- 恢复自动提交
索引
索引(Index)是帮助MYSQL高效获取数据的数据结构
-
主键索引 (PRIMARY KEY)
-
唯一的标识,主键不可重复,只能有一个列作为主键
-
-
唯一索引(UNIQUE KEY)
-
避免重复的列出现,唯一索引可以重复,多个列都可以标识唯一索引
-
-
常规索引(KEY/Index)
-
默认的,index,key关键字来设置
-
-
全文索引(FullText)
-
在特定数据库引擎下才有,Myisam
-
快速定位数据
-
基础语法:
-- ==================索引==========================
-- 1.在创建表的时候给字段添加索引
-- 2.创建表完毕后,增加索引
-- 显示所有的索引信息
SHOW INDEX FROM `student`;
-- 增加一个(索引名) 列名
ALTER TABLE `student` ADD INDEX s_name (`s_name`);
-- 创建索引
-- id_表明_字段名
-- create index 索引名 on 表(字段)
CREATE INDEX id_student_s_birth ON s_birth(`s_birth`);
-- EXPLAIN 分析sql执行的状况
EXPLAIN SELECT * FROM student; -- 非全文索引
EXPLAIN SELECT * FROM WHERE MATCH(`s_name`) AGAINST('刘');
索引原则
-
索引不是越多越好
-
不要对进程变动数据加索引
-
小数据量的表不需要加索引
-
索引一般加在常用来查询的字段上
索引的数据结构
Hash类型的索引
Btree:InnoDB的默认数据结构
权限管理
可视化:
命令操作语法:
-- ===================权限=============================
-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码'; identified
CREATE USER chenlei1 IDENTIFIED BY '123456';
-- 修改密码(--当前用户)
SET PASSWORD = PASSWORD('123456');
-- 修改密码(--指定用户)
SET PASSWORD FOR chenlei1=PASSWORD('111111');
-- 重命名 RENAME USER 原用户名 TO 新用户名;
RENAME USER chenlei1 TO chenchen;
-- 用户授权 ALL PRIVILEGES 全部权限,*.*意思为(库.表)
-- ALL PRIVILEGES 除了不能有root的grant(授予其他用户权限)权限,其他都能
GRANT ALL PRIVILEGES ON *.* TO chenchen;
-- 查看权限
SHOW GRANTS FOR chenchen; -- 查看指定用户权限 Grants for chenchen@% GRANT ALL PRIVILEGES ON *.* TO 'chenchen'@'%' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9'
SHOW GRANTS FOR root@localhost; -- 查看root用户 GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' WITH GRANT OPTION
-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM chenchen;
-- 删除用户
DROP USER chenchen;
MySQL备份
作用:
-
保证数据不丢失
-
数据转移
MySQL数据库备份方式
-
直接拷贝物理文件
-
在Sqlyog这种可视化工具手动导出
-
使用命令行到处mysqldump 命令行使用
-- 单张表 导出 C:\Users\16225>mysqldump -hlocalhost -uroot -p123456 school student> d:1.sql -- 多张表 导出 C:\Users\16225>mysqldump -hlocalhost -uroot -p123456 school student result> d:2.sql -- 整个数据库 导出 C:\Users\16225>mysqldump -hlocalhost -uroot -p123456 school > d:3.sql -- 数据库导入 C:\Users\16225>mysql -uroot -p123456 mysql> use school; Database changed mysql> source d:3.sql
设置数据库的步骤
-
收集信息,分析需求
-
用户表(用户登录注销,用户的个人信息,写博客,创建分类)
-
分类表(文章分类,谁创建的)
-
文章表(文章的信息)
-
评论表
-
友链表(友链信息)
-
自定义表(系统信息,某个关键的字,或者一些主字段) key : value
-
说说表(发表心情.. id... conte...create. _time)
-
-
标识实体(把需求落地到每个字段)
-
标识实体之间的关系
-
写博客: user --> blog
-
创建分类: user -> category
-
关注: user ->user
-
友链: links
-
评论: user-user-bl
-
数据库三大范式
三大范式
第一范式(1NF)
原子性:保证每一列不可再分
第二范式(2NF)
前提:满足第一范式
没一张表只描述一件事情
第三范式(3NF)
前提:满足第一范式和第二范式
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关
(规范数据库设计)
规范性 和 性能的问题
关联查询的表不得超过三张表
-
考虑商业化的需求和目标,(成本、用户体验)数据库性能更加重要
-
在规范性能问题的时候,需要适当的考虑一下 规范性
-
故意给某些表增加一些冗余的字段(从多表查询变为单表查询)
-
故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
JDBC(重点)
数据库驱动
新建lib目录,把数据库jar包粘贴到lib目录下,右键add as library 添加到库
-- 创建数据库
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', '1isi@sina.com', '1981-12-04'),
(3,'wangwu' , '123456' ,'wangwu@sina.com','1979-12-04');
-- =================================
import javax.print.attribute.standard.MediaSize;
import java.sql.*;
public class JDBCFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 创建驱动
Class.forName("com.mysql.jdbc.Driver");
// 用户信息和url
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String user="root";
String pwd="123456";
//连接成功,数据库对象,
Connection connection = DriverManager.getConnection(url, user, pwd);
//执行sql的对象 Statement 为执行的对象
Statement statement = connection.createStatement();
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("pwd="+resultSet.getObject("password"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birth="+resultSet.getObject("birthday"));
}
if (resultSet!=null){
resultSet.close();
}
if (statement!=null){
statement.close();
}
if (connection!=null){
connection.close();
}
}
}
JDBC步骤:
-
加载驱动
-
连接数据库DriveManager
-
获得执行sql对象的statement
-
获得返回的结果集(查询才有的)
-
释放连接
DriverManager
Class.forName("com.mysql.jdbc.Driver"); //固定写法
Connection connection = DriverManager.getConnection(url, user, pwd);
/*
connection代表数据库
数据库设置自动提交
事务提交
事务回滚
*/
connection.rollback();
connection.commit();
connection.getAutoCommit();
URL
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true"; //Mysql--3306 //协议://地址:端口号/数据库名 //oralce--1521 //jdbc:oralce:thin:@localhost:1521:sid
Statement 执行SQL对象 PrepareStatement执行SQL对象
statement.executeQuery(); //查询 返回 ResultSet
statement.executeUpdate(); //插入、更新、删除 返回受影响的行数
statement.execute(); //任何sql语句
ResultSet 查询指定的结果集:封装了所有查询结果
获得指定的数据类型
resultSet.getObject(); //任何类型都可以用这个
resultSet.getInt(); //获取整型
resultSet.getFloat();//获取单精度浮点数
resultSet.getDouble();//获得双精度浮点数
resultSet.getString(); //获得字符串类型
遍历
resultSet.next(); //移动到后一个 resultSet.previous(); //移动到前一个 resultSet.beforeFirst(); //移动到最前面 resultSet.afterLast(); //移动到最后面
释放连接
if (resultSet!=null){
resultSet.close();
}
if (statement!=null){
statement.close();
}
if (connection!=null){
connection.close();
}
//关闭资源有后向前关闭
Statement对象
代码实现
驱动实现
package com.chenlei.lesson02.utils;
import jdk.nashorn.internal.ir.IfNode;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver=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);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//释放资源
public static void release(Connection con, Statement st, ResultSet re){
try {
if (re!=null){
re.close();
}
if (st!=null){
st.close();
}
if (con!=null){
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
增
package com.chenlei.lesson02;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet re = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql="INSERT INTO users(id, `name`, `password`,email, birthday)\n" +
"VALUES(5, 'chenlei', '123456', 'superstudyc@163.com', '2020-12-04')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(conn,st,re);
}
}
}
删
package com.chenlei.lesson02;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet re = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql="DELETE FROM `users` WHERE id=3;";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("删除成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(conn,st,re);
}
}
}
改
package com.chenlei.lesson02;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet re = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql="UPDATE `users` SET `name`='chenlong',`password`='11111',`email`='2401620421@qq.com',`birthday`='2020-12-04' WHERE id=2;";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("更新成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(conn,st,re);
}
}
}
查
package com.chenlei.lesson02;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet re=null;
try {
conn=JdbcUtils.getConnection();
st=conn.createStatement();
String sql="SELECT `name` FROM users WHERE id=4;";
re=st.executeQuery(sql);
while (re.next()){
System.out.println(re.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,re);
}
}
}
配置文件
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456
SQL注入问题
数据库漏洞
package com.chenlei.lesson02;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Sql注入 {
public static void login(String username,String password){
Connection conn=null;
Statement st=null;
ResultSet re=null;
try {
conn= JdbcUtils.getConnection();
st=conn.createStatement();
String sql="select * from users";
re=st.executeQuery(sql);
while (re.next()){
System.out.println(re.getString("name"));
System.out.println(re.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,re);
}
}
public static void main(String[] args) {
login("''or 1=1 "," '' or 1=1");
}
}
PreparedStatement对象
作用:防止SQL注入,效率更高
增
package com.chenlei.lesson03;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestIsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet re = null;
try {
conn = JdbcUtils.getConnection();
String sql = "insert into users (id, name, password, email, birthday) VALUES (?,?,?,?,?)";
st = conn.prepareStatement(sql);
st.setInt(1,8);
st.setString(2,"赵六");
st.setString(3,"12789");
st.setString(4,"789@qq.com");
st.setString(5,"2023-04-04");
int i = st.executeUpdate();
if (i>0){
System.out.println("插入数据成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,re);
}
}
}
删
package com.chenlei.lesson03;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection con=null;
PreparedStatement st=null;
ResultSet re=null;
try {
con = JdbcUtils.getConnection();
//值用?标识
String sql="delete from users where id=?";
st= con.prepareStatement(sql); //预编译 先写sql 不执行
//给预编译的?赋值
st.setInt(1,8);
int i = st.executeUpdate();
if (i>0){
System.out.println("删除成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(con,st,re);
}
}
}
改
package com.chenlei.lesson03;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection con=null;
PreparedStatement st=null;
ResultSet re=null;
try {
con = JdbcUtils.getConnection();
//值用?标识
String sql="update users set `name`=?, password=?, email=? ,birthday=? where id=?";
st= con.prepareStatement(sql); //预编译 先写sql 不执行
//给预编译的?赋值 parameterindex是按照?来的,第一个?第一列以此类推
st.setString(1,"高兴");
st.setString(2,"789456");
st.setString(3,"1622517097@163.com");
st.setString(4,"2020-10-20");
st.setInt(5,1);
int i = st.executeUpdate();
if (i>0){
System.out.println("修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(con,st,re);
}
}
}
查
package com.chenlei.lesson03;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestSelect {
public static void main(String[] args) {
Connection con=null;
PreparedStatement st=null;
ResultSet re=null;
try {
con=JdbcUtils.getConnection();
String sql="select `name`,password from users where id=?;";
st= con.prepareStatement(sql);
st.setInt(1,1);
re = st.executeQuery();
while (re.next()){
System.out.println("用户名为:"+re.getString("name"));
System.out.println("密码为:"+re.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(con,st,re);
}
}
}
用IDEA连接数据库
连接数据库
选择你想要显示的数据库
命令行输入sql语句
自动提交事务
ACID原则
原子性:要么成功,要么失败
一致性:提交前后数据总数不变
隔离性:多个进程互不干扰
持久性:事务一旦提交不可恢复,被持久化到数据库当中
隔离性产生的问题:
脏读:一个事务读取了另一个没有提交的事务
不可复读:在一个事务内重复读取数据,表数据发生了改变
虚度(幻读):在一个事务内,读取到了别人插入的数据,导致前后读取出来的数据不一致
package com.chenlei.lesson04;
import com.chenlei.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestWork {
public static void main(String[] args) {
Connection con=null;
PreparedStatement st=null;
ResultSet re=null;
try {
con=JdbcUtils.getConnection();
con.setAutoCommit(false); //关闭自动提交,默认事务自动开启 和sql里面不一样
String sql1="update account set money=money-100 where id=1";
st=con.prepareStatement(sql1);
st.executeUpdate();
String sql2="update account set money=money+100 where id=2";
st=con.prepareStatement(sql2);
st.executeUpdate();
con.commit(); //提交事务
System.out.println("成功");
} catch (SQLException e) {
try {
con.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
数据库连接池
最小连接数:
最大连接数:
等待超时:
编写连接池:实现一个DataSource接口
开源数据源实现
DBCP
C3P0
Druid:阿里巴巴
使用了这些数据库连接池之后,我们在项目中就不需要编写连接数据库的代码了
DBCP
需要得jar包:commons-pool-1.6jar commons-dbcp-1.4jar
配置文件:
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456 # initialSize=10 #最大连接数量 maxActive=50 # maxIdle=20 # minIdle=5 # maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:“user” 与 “password” 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=gbk #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
package com.chenlei.lesson05.utils;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static DataSource dataSource = null;
static {
try {
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //从数据源中获取连接
}
//释放资源
public static void release(Connection con, Statement st, ResultSet re) {
try {
if (re != null) {
re.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
C3P0
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/bd3</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!-- 初始化申请的连接数量 -->
<property name="initialPoolSize">5</property>
<!-- 最大的连接数量 -->
<property name="maxPoolSize">10</property>
<!-- 超时时间 3秒 -->
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="Mysql">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
代码:
package com.chenlei.lesson05.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils_C3P0 {
private static DataSource dataSource = null;
static {
try {
//配置文件写法
dataSource = new ComboPooledDataSource("Mysql");
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //从数据源中获取连接
}
//释放资源
public static void release(Connection con, Statement st, ResultSet re) {
try {
if (re != null) {
re.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

浙公网安备 33010602011771号