MySQL(狂神说笔记)

发布时间:2024-09-09 10:01

MySQL(狂神说笔记)

1.初始数据库

1.1为什么学习数据库?

1.岗位需求

2.现在的世界,大数据时代,得数据库者得天下。

3.被迫需求: 存数据

4.数据库是所有软件体系中最核心的存在: DBA

1.2什么是数据库?

数据库(DB,DataBase)

概念:数据仓库,软件 安装在操作系统上(windows,Linux,mac…) 可以存放大量的数据。

作用:存放数据,管理数据。

1.3 数据库分类

关系型数据库

  • MySQL ,Oracle,Sql Server,DB2, SQL Lite
  • 通过表和表之间,行和列之间的关系进行数据的存储,学员信息表,考勤表。

非关系型数据库:(NoSQL) Not Only

  • Redis , MongDB
  • 非关系型数据库,对象存储,通过对象的自身的书写来决定/

DBMS(数据库管理系统)

  • 数据库的管理软件,科学有效的管理我们的数据。维护和获取数据。
  • MySQL, 数据库管理系统!

1.4 MySQL简介

安装

不要使用exe 文件,因为删不干净

尽可能使用压缩包文件

1.5MySQL安装教程

这里建议大家使用压缩版,安装快,方便.不复杂.

软件下载

mysql5.7 64位下载地址:

电脑是64位的就下载使用64位版本的!

安装步骤

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、连接上测试出现以下结果就安装好了

1.6 安装可视化工具 SQLyog

无脑安装

1.7 连接数据库

mysql -uroot -p -- 连接数据库

update mysql.user set authentication_string=password(\'123456\') where user=\'root\'and Host = \'localhost\'; -- 修改密码

flush privileges; -- 刷新权限

-- 所有的语句(除切换语句外) 都使用;结尾

show databases; -- 查看所有的数据库

use userdb -- 切换数据库 use + 数据库名

show tables -- 查看数据库中所有的表
describe userdb -- 查看数据库中所有表的信息

DROP DATABASE IF EXISTS myschool -- 删除数据库


create database westos -- 创建一个数据库

exit -- 退出链接

-- 单行注释(SQL本来的注释)
/*
多行注释
*/

数据库 xxx 语言

DDL 定义

DML 操作

DQL 查询

DCL 控制

2.操作数据库

操作数据库 > 操作数据库中的表 > 操作数据库中表的数据

2.1操作数据库(了解)

1.创建数据库

CREATE database if not EXISTS myschool

2.删除数据库

drop database [if EXISTS] myschool

3.使用数据库

use myschool

4.查询数据库

SHOW DATABASES

2.2 数据库的列类型

数值

  • tinyint 十分小的数据 一个字节
  • smallint 较小的数据 2个字节
  • mediumint 中等大小的数据 3个字节
  • int 标准的整数 4个字节 常用的 int
  • bigint 较大的数据 8个字节
  • float 浮点数 4个字节
  • double 浮点数 8个字节
  • decimal 字符串形式的浮点数 金融计算时一般使用

字符串

  • char 字符固定大小的 0~255
  • varchar 可变字符串 0~65535 常用的 String
  • tinytext 微型文本 2^8 - 1
  • text 文本串 2^16 - 1 保存大文本

时间日期

java.util.Date

  • date YYYY-MM-DD 日期格式
  • time HH:mm:ss 时间格式
  • datetime YYY-MM-DD HH:mm:ss 最常用的时间格式
  • timestamp 时间戳 , 1970.1.1到现在的毫秒数 也较为常用
  • year 年份表示

null

  • 表示没有值,未知
  • 注意,不要使用NULL进行运算,结果为NULL

2.3 数据库的字段属性(重点)

Unsigned

  • 无符号整数
  • 声明了该列不能为负数

zerofill:

  • 0填充的
  • 不足的位数,用0来填充

自增:

  • 通常理解为自增,自动在上一条的记录的数据上加1
  • 通常用来设计唯一的主键~index,必须是整形数据
  • 可以自定义设计主键自增的起始值和步长

非空 NULL not null

  • 假设设置为not null ,如果不给它赋值,就会报错!
  • NULL,如果不填写值,默认就是null!

拓展(听听就好)

/*每一个表,都必须存在以下五个字段!未来做项目用的,表示一个记录存意义

id 主键
`version`   乐观锁
is_delete   伪删除
gmt_create   创建时间
gmt_update   修改时间

*/

2.4 创建表

-- 注意点,使用英文(),表的名称 和 字段 尽量使用 ``括起来
-- AUTO_INCREMENT 自增
-- 字符串使用,单引号括起来!
-- 所有的语句后面加,(英文的),最后一个不用加
-- PRIMARY KEY(`id`) 主键,一般一个表只有一个唯一的主键!


CREATE TABLE IF NOT EXISTS `student`(
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT \'学号\',
	`name` VARCHAR(20) 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(50) DEFAULT NULL COMMENT \'家庭住址\',
	`email` VARCHAR(30) DEFAULT NULL COMMENT \'邮箱\',
	PRIMARY KEY(`id`)
	

)ENGINE=INNODB DEFAULT CHARSET=utf8

格式

CREATE TABLE [IF NOT EXISTS] `表名`(

    `字段名` 列类型 [属性] [索引] [注释]
    `字段名` 列类型 [属性] [索引] [注释]
    ......
    `字段名` 列类型 [属性] [索引] [注释]
    
)[表类型] [字符集设置][注释]

常用命令


SHOW CREATE DATABASE `myschool` -- 查看数据库的创建语句

SHOW CREATE TABLE student  -- 查看数据表的创建语句

DESC student  -- 显示表的结构

2.5 数据表的类型

-- 关于数据库引擎
/*
INNODB 默认使用
MYISAM 早些年使用的
*/
MYISAM INNODB
事务支持 不支持 支持
数据行锁定 不支持 支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间的大小 较小 较大,约为2倍

常规使用操作:

  • MYISAM 节约空间,速度较快
  • INNODB : 安全性高,事务的处理,多表多用户操作

在物理空间存在的位置

所有的数据库文件都存在date目录下,一个文件夹就相当于一个数据库。

本地还是文件的存储!

MySQL 引擎在物理文件上的区别

  • InnoDB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
  • MYISAM对应文件
    • *.frm 表结构的定义文件
    • *.MYD 数据文件(data)
    • *.MYI 索引文件(index)

设置数据库的字符集编码

CHARSET=utf8

不设置的话,会是mysql默认的字符集编码~ (不支持中文)

MySQL的默认编码是Latin1,不支持中文

在my.ini中配置默认的编码

character-set-server=utf8

2.6修改和删除表

修改表

-- 修改表的信息 
-- 对表进行修改名字   ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE student RENAME AS student1

-- 添加字段名  ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE student1 ADD grade INT(6)

-- 修改字段 (修改字段名 和 约束)
-- 修改字段约束   ALTER TABLE 表名 MODIFY 字段名 列属性
ALTER TABLE student1 MODIFY grade VARCHAR(10)
-- 修改字段名称   ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性
ALTER TABLE student1 CHANGE grade grade1 INT(2)

-- 删除表中的字段名   ALTER TABLE 表名 DROP 字段名
ALTER TABLE student1 DROP grade1

删除表

DROP TABLE IF EXISTS teacher

创建和删除表尽量加上条件语句

注意点

  • `` 字段名尽量使用 这个进行包裹
  • 注释 – /**/
  • sql大小写不敏感,尽量使用小写
  • 所有的符号都使用英文!

3.MySQL数据管理

3.1外键(了解即可)

方式一 : 在创建表的时候就进行外键连接。


CREATE TABLE `grade` (
  `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT \'年级编号\',
  `gradename` VARCHAR(20) DEFAULT NULL COMMENT \'年级名称\',
  PRIMARY KEY(`gradeid`)

)ENGINE=INNODB DEFAULT CHARSET=utf8; 

-- 在创建表的时候就进行外键连接
 CREATE TABLE IF NOT EXISTS `student`( 
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT \'学号\',
	 `name` VARCHAR(20) 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(8) NOT NULL COMMENT \'年级编号\',
	 `address` VARCHAR(50) DEFAULT NULL COMMENT \'家庭住址\',
	 `email` VARCHAR(30) DEFAULT NULL COMMENT \'邮箱\',
	  PRIMARY KEY(`id`),
	  KEY `FK_gradeid`(`gradeid`),
	  CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
	  
)ENGINE=INNODB DEFAULT CHARSET=utf8; 

删除表的时候,如果该表含有外键;那么,该表不能进行删除。必须引用外键的表被删除后才能进行删除。

方式二:在创建表的时候就进行外键连接


CREATE TABLE `grade` (
  `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT \'年级编号\',
  `gradename` VARCHAR(20) DEFAULT NULL COMMENT \'年级名称\',
  PRIMARY KEY(`gradeid`)

)ENGINE=INNODB DEFAULT CHARSET=utf8; 

-- 在创建表的时候就进行外键连接
 CREATE TABLE IF NOT EXISTS `student`( 
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT \'学号\',
	 `name` VARCHAR(20) 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(8) NOT NULL COMMENT \'年级编号\',
	 `address` VARCHAR(50) DEFAULT NULL COMMENT \'家庭住址\',
	 `email` VARCHAR(30) DEFAULT NULL COMMENT \'邮箱\',
	  PRIMARY KEY(`id`)
	  
)ENGINE=INNODB DEFAULT CHARSET=utf8; 

-- 在表创建好的时候,进行外键的添加
ALTER TABLE student ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)

以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰,这里了解即可)

最佳实践

  • 数据库就是单纯的表,只好用来存数据,只有行(数据)和列(字段)
  • 我们想使用多张表的数据,想使用外键(程序去实现)

3.2DML语言(全部记住)

数据库的意义:用来存储数据,管理数据。

  1. insert

  2. update

  3. delete

3.3 添加

insert


-- 插入数据  INSERT INTO 表名 (`字段名1`,`字段名2`,`字段名3`) VALUES(`值1`),(\'值2\')....
-- 其他要么默认为NULL或自增主键
INSERT INTO grade (`gradename`) VALUES(\'大一\')

-- 如果前面没有相应的字段提示,那么字段与值之间必须一一对应
INSERT INTO grade VALUES (\'大二\')  -- 此处相当于执行 INSERT INTO grade VALUES (\'大二\',null)不匹配

-- 插入多个数据

INSERT INTO grade (`gradename`) VALUES(\'大二\'),(\'大四\')

语法:INSERT INTO 表名 (字段名1,字段名2,字段名3) VALUES(值1),(\'值2\')....

注意事项:

  1. 字段和字段之间必须使用英文的逗号隔开
  2. 字段可以省略,但是后面的值必须要一一对应,不能少
  3. 可以同时插入多条数据,VALUES后面的值,需要使用,隔开即可 使用英文逗号。

3.4 修改

修改 谁 (条件) set 原来的值=新值

-- 修改 谁 (条件)  set 原来的值=新值
-- 修改简介
UPDATE `student` SET `name`=\'狂神\' WHERE id=1 


-- 整列修改
UPDATE `student` SET `name`=\'长江七号\'


UPDATE `student` SET `email`=\'2398291@qq.com\' WHERE id = 1

-- 语法
-- UPDATE 表名 SET column_name=value,[column_name=value] WHERE column_name=特定的值

条件:where 子句 运算符 id等于某个值,大于某个值,小于某个值

返回的是 布尔值

操作符 含义 范围 结果
= 等于 5=6 false
<> 或 != 不等于 5<>6 true
>
<
>=
<=
BETWEEN…AND… [2,5]
AND 且 && 5>1 AND 1<2 false
OR 或 || 5>1 OR 1<2 true

-- 通过多个条件定位数据
UPDATE student SET `sex`=\'女\' WHERE `name`=\'长江七号\' AND `pwd`=\'12345\' 

语法: UPDATE 表名 SET column_name=value,[column_name=value] WHERE column_name=特定的值

注意:

  • column_name 是数据库中的列,需要加上``

  • 条件: 如果没有筛选条件,就会修改所有的列

  • value,是一个具体的值,也可以是一个变量

  • 多个设置的属性之间使用英文的逗号隔开

    UPDATE student SET `birthday`=CURRENT_TIME WHERE `name`=\'长江七号\' AND `sex`=\'女\'
    

3.5删除

delete命令

语法: delete from 表名 [where 条件]

-- delete 删除数据 (删除表的全部数据) 不建议使用
DELETE FROM `student` 
-- 删除指定的数据
DELETE FROM `student` WHERE `id`=1

TRUNCATE 命令

作用:完全清空数据库中表中的数据

-- 删除数据库表中的所有的数据
TRUNCATE `student`

delete 和 TRUNCATE 的区别

  • 相同点: 都可以清空表中的数据 ,都不会表的结构和约束

  • 不同点 :

    • TRUNCATE 会使被设置为主键的列归零
    • TRUNCATE 不会影事务

了解即可:delete删除的问题,重启数据库,现象

  • InnoDB 自增列会从1开始(存在内存当中的,断电即失)
  • MyISAM 会继续从上一个自增量开始(存在文件中的,不会丢失)

4.DQL查询(最重点)

4.1DQL

[Data Query Language 数据查询语言]

  • 所有的查询操作都使用它 select

  • 简单的以及复杂的查询都是使用它

  • 数据库中最核心的语言,最重要的语句

  • 使用频率最高的语句

    顺序很重要

\"MySQL(狂神说笔记)_第1张图片\"

4.2指定查询字段

-- 查询学生信息表的所有字段

SELECT * FROM student

-- 查询学生信息表的指定字段

SELECT `studentno`,`studentname` FROM student

-- 起别名  AS   字段名 as 新名字   表名 as  新名字  别名只是在此语句中起作用,而实际上并未改变数据库中的字段名和表名

SELECT `studentno` AS 学号,`studentname` AS 学生姓名 FROM student AS s

-- 函数 concat

SELECT CONCAT(\'姓名:\',`studentname`) AS 新名字 FROM student 

语法 :SELECT 字段,... FROM 表名

有的时候,列名字不是那么的见名知义。所以我们会对其起别名 AS 字段名 as 新名字

去重 :distinct 直接加在需要去重的字段名前,就能对其去重

-- 对查询出来的数据进行去重 
SELECT DISTINCT `studentno` FROM `student`


数据库的列(表达式)

-- 查询数据库的版本(函数)
SELECT VERSION() 
-- 对算术表达式进行计算(表达式)
SELECT 100*3 - 1 AS 计算结果

-- 显示查询步长(变量)
SELECT @@auto_increment_increment


SELECT `studentno`,`studentresult` + 1 AS 新成绩 FROM `result` -- 变量可以进行计算

数据库中的表达式:文本值,列,NULL,函数,计算表达式,系统变量…

select 表达式 from 表

4.3 where 条件子句

作用:查询符合条件的值

运算符

运算符 语法 描述
and && a and b a && b 两个为真才为真
or || a or b a ||b 两个为假才为假
Not ! not a !a 取反

尽量使用英文

-- 查询学生成绩在 85~100之间的学生学号 和 学生成绩
SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult`>=85 AND `studentresult`<=100


SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult`>=85 && `studentresult`<=100

SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult` BETWEEN 85 AND 100


-- 查询学生成绩不等于60的学生学号 和 学生成绩

SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult` != 68

SELECT `studentno`,`studentresult` FROM result
WHERE NOT `studentresult`=60

模糊查询:比较运算符

运算符 语法 描述
is null a is null 如果a 为空则返回真
is not null a is not null 如果a 不为空则返回真
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其中的某一个值中,则返回真。

like 结合 % (0 到任意个字符) _(一个字符)

SELECT * FROM student
-- 查询姓赵的同学信息
SELECT * FROM student
WHERE `studentname` LIKE \'赵%\'

-- 查询姓赵且名字个数为2的同学信息
SELECT * FROM student
WHERE `studentname` LIKE \'张_\'

-- 查询住址中包含朝字的同学信息
SELECT * FROM student
WHERE `address` LIKE \'%朝%\'

-- 查询学生学号是(1000,1001)这两个数中其中一个的学生的信息

SELECT * FROM student
WHERE `studentno` IN (1000,1001)

-- 查询出生日期 为NULL的学生信息
SELECT * FROM student
WHERE `borndate` IS NULL


-- 查询出生日期 不为NULL的学生信息
SELECT * FROM student
WHERE `borndate` IS NOT NULL

4.4联表查询

join 对比

\"MySQL(狂神说笔记)_第2张图片\"

思路:

  1. 分析需求,分析查询的字段来自哪些表(连接查询)
  2. 确定使用哪种连接查询 ?(7种)

确定交叉点(这两个表中哪个数据是相同的)

判断的条件:学生表的 studentNo = 成绩表 studentNo

--  ===========联表查询===========

-- 查询参加了考试的同学的 studentno  studentname subjectno studentresult
/*
1. 分析需求,分析查询的字段来自哪些表(连接查询)
2. 确定使用哪种连接查询 ?(7种)

确定交叉点(这两个表中哪个数据是相同的)

判断的条件:学生表的 studentNo = 成绩表  studentNo
*/

--  INNER JOIN 实现的是 两个表之间的并集
SELECT s.studentno,studentname,subjectno,studentresult 
FROM student s
INNER 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

-- RIGHT JOIN 以右表为准,会返回右表的所有信息
SELECT s.studentno,studentname,subjectno,studentresult 
FROM student s
RIGHT JOIN result r
ON s.studentno=r.studentno


-- join on  连接查询
-- where 等值查询

字段都是并集

操作 描述
Inner join 如果表中至少有一个匹配,就返回行(不会查出多余的字段和空字段,使用最为频繁)
left join 会从左表中返回所有的值,即使右表中没有匹配
right join 会从右表中返回所有的值,即使左表中没有匹配
--  查询参加了考试的所有学生的 studentno studentname subjectname studentresult

SELECT s.studentno,studentname,subjectname,studentresult
FROM result r
LEFT JOIN student s
ON r.studentno=s.studentno
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno -- subjectname 没有模棱两可的地方

-- 我要查询哪些数据 select...
-- 从哪几个表中 查 from 表 xxx  join  连接的表 on  交叉条件
-- 假设 存在一种多张表的查询,慢慢来,先查询两张表然后再慢慢增加

-- from a left join b
-- from a right join b

自连接

核心就是:将自己这张表拆成一模一样的两张表进行操作

父类:

categoryid categoryname
2 信息技术
3 软件开发
5 美术设计

子类:

pid categoryid categoryname
3 4 数据库
3 6 web开发
5 7 ps技术
2 8 办公信息

父类和子类的连接表

pcategoryname categoryname
软件开发 数据库
软件开发 web开发
美术技术 ps 技术
信息技术 办公信息
-- 自连接
SELECT a.categoryname AS \'父栏目\',b.categoryname AS \'子栏目\'
FROM category a ,category b
WHERE a.categoryid=b.pid
-- where 等值查询

4.5 分页和排序

排序

-- 排序 升序asc  降序 desc
-- ORDER BY 字段名称 排序方式

SELECT * FROM result
ORDER BY studentresult DESC

分页

为什么需要分页?

缓解数据库压力,给人的体验更好,瀑布流

-- 分页
SELECT * FROM result
LIMIT 1,2

-- 语法: limit (起始值,页面大小)

-- [n : 总页数]
-- [(n - 1) * pagesize : 起始值] 
-- [pagesize : 页面大小]
-- [总页数 = 总数 / pagesize]

语法:limit (起始值,页面大小)

4.6 子查询

where (这个值是计算出来的)

本质: 在where语句中嵌套一个子查询语句

where(select * from 表名)

-- 查询 分数不小于80 且 课程名称为 高等数学-1 的学生的 学号 和名字
-- 联表查询
SELECT s.`studentno`,`studentname`
FROM student s 
INNER JOIN result r
ON s.`studentno`=r.`studentno`
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`
WHERE `studentresult`>80 AND `subjectname`=\'高等数学-1 \'


SELECT s.`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`=\'高等数学-1 \'
)

-- 子查询  在改造(由里及外)
SELECT `studentno`,`studentname` FROM student WHERE `studentno` IN (
	SELECT `studentno` FROM result WHERE `studentresult`>80 AND `subjectno` = (
			SELECT `subjectno` FROM `subject` WHERE `subjectname`=\'高等数学-1 \'
	)
) 

4.7 select小结

\"MySQL(狂神说笔记)_第3张图片\"

5. MySQL 常用函数

5.1常用函数

-- ==========常用函数========
--  数学运算
SELECT ABS(-8)  -- 绝对值
SELECT CEILING(9.4)  -- 向上取整
SELECT FLOOR(9.8)-- 向下取整

SELECT RAND() --  0~1之间的随机数

SELECT SIGN(10) -- 判断一个数的符号 0-0  负数返回-1,正数返回1

--  字符串函数
SELECT CHAR_LENGTH(\'狂神说努力就会成功\')	-- 返回字符串长度
SELECT CONCAT(\'我\',\'爱\',\'你们\')	--  拼接字符串
SELECT INSERT(\'我爱编程helloworld\',1,2,\'超级热爱\')	--  从某个位置开始替换字符串
SELECT LOWER(\'KUANGSHEN\')	
SELECT UPPER(\'kuangshen\')  			--  转换大小写
SELECT INSTR(\'kaungshen\',\'sh\')   		-- 返回第一次出现的字串的索引
SELECT REPLACE(\'狂神说坚持就能成功\',\'坚持\',\'努力\')	--  替换出现的指定字符串
SELECT SUBSTR(\'狂神说坚持就能成功\',4,6)	--  截取指定的字符串  (源字符串截取的位置,截取的长度)

SELECT REVERSE(\'清晨我上马\')  -- 反转字符串


-- 时间日期函数
SELECT CURRENT_DATE()  -- 获取当前日期
SELECT CURDATE()  -- 获取当前日期
SELECT NOW()   -- 获取当前的时间

SELECT LOCALTIME()  --  本地时间

SELECT SYSDATE()   -- 获去系统时间

SELECT YEAR(NOW())
SELECT MONTH(NOW())
SELECT DAY(NOW())
SELECT HOUR(NOW())
SELECT MINUTE(NOW())
SELECT SECOND(NOW())


-- 系统
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()

5.2聚合函数(常用)

函数名称 描述
COUNT() 计数
SUM() 求和
AVG() 求平均值
MAX() 求最大值
MIN() 求最小值
-- =======聚合函数====

SELECT COUNT(subjectno) FROM result  -- COUNT(指定字段)  会忽略null值

SELECT COUNT(*) FROM result   --  COUNT(*)  不会忽略所有的null值   本质 : 计算行数
SELECT COUNT(1) FROM result	--  COUNT(1)  不会忽略所有的null值   本质 : 计算行数


SELECT SUM(`studentresult`) FROM result
SELECT AVG(`studentresult`) FROM result
SELECT MAX(`studentresult`) FROM result
SELECT MIN(`studentresult`) FROM result


--  group by 字段 以什么字段分组

-- HAVING 等价于 where  但是 where时表示在分组之前  HAVING 是在分组之后

5.3数据库级别的MD5加密(扩展)

什么是MD5?

主要增强算法复杂度和不可逆性。

MD5不可逆,具体的值的md5是一样的

MD破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值

CREATE TABLE `test05`(
   `id` INT(4) NOT NULL,
   `name` VARCHAR(20) NOT NULL,
   `pwd` VARCHAR(60) NOT NULL,
   PRIMARY KEY(`id`)

)ENGINE=INNODB DEFAULT CHARSET=utf8

-- 明文密码
INSERT INTO `test05` VALUES(1,\'张三\',\'123456\'),
(2,\'李四\',\'123456\'),
(3,\'王五\',\'123456\')

DROP TABLE test05

-- 加密
UPDATE test05 SET pwd=MD5(pwd) WHERE id=1  -- 对指定的密码加密

UPDATE test05 SET pwd=MD5(pwd) -- 对全部的密码进行加密

-- 插入的时候进行 加密
INSERT INTO test05 VALUES(4,\'赵四\',MD5(\'567899\'))

-- 两次MD5加密后 密码就是相同了的

-- 如何校验 : 先将顾客输入的密码进行加密,然后 在进行比对
SELECT * FROM test05 WHERE `name`=\'张三\' AND pwd=MD5(\'123456\')

6.事务

6.1 什么是事务?

要么成功,要么失败。

将一个 SQL 放在一个批次去执行。

事务原则:ACID原则 原子性 一致性 持久性 隔离性 脏读 不可重复读 幻读

原子性

要么都成功,要么都失败。

一致性

事务前后的完整性要保证一致 比如转钱前后的钱总数一致

隔离性

事务的隔离性是多个用户并发的访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,事物之间要相互隔离。

持久性

事务一旦提交,那么就会被持久化到数据库。

脏读:

指一个事务读取了另外一个事务未提交的数据。

不可重复读:

在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

幻读:

是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

执行事务

-- ======事务处理=======

-- 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 `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

DROP TABLE `account`

INSERT INTO `account` (`name`,`money`)VALUES(\'A\',2000.00),(\'B\',10000.00)

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(狂神说笔记)_第4张图片\"

7.索引

MySQL官方对索引的定义为:索引是帮助MySQL高效获取数据的数据结构。

索引的本质:索引是数据结构。

7.1 索引的分类

在一个表中,主键索引唯一,而唯一索引可以为多个

  • 主键索引(PRIMARY KEY)
    • 唯一的标识,主键不可重复,只有一个列作为主键
  • 唯一索引(UNIQUE KEY)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识为标识位 唯一索引
  • 常规索引(KEY/INDEX)
    • 默认的
  • 全文索引(FullText)
    • 在特定的数据库引擎下才有,MYISAM
    • 快速定位数据。
--  =======索引====


SHOW INDEX FROM student  -- 显示所有的索引信息

ALTER TABLE student ADD FULLTEXT INDEX `studentname`(`studentname`)  -- 向表中添加索引

--  EXPLAIN查看sql语句的执行情况
-- EXPLAIN + 相应的sql语句

7.2 测试索引

测试索引


-- P31 创建app_user表格
CREATE TABLE `app_user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT \'\',
`eamil` VARCHAR(50) NOT NULL,
`phone` VARCHAR(20) DEFAULT \'\',
`gender` TINYINT(4) UNSIGNED DEFAULT \'0\',
`password` VARCHAR(100) NOT NULL DEFAULT \'\',
`age` TINYINT(4) DEFAULT NULL,
`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=utf8


-- 插入100万数据.
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`,`eamil`,`phone`,`gender`)VALUES(CONCAT(\'用户\',i),\'19224305@qq.com\',\'123456789\',FLOOR(RAND()*2));
		SET i=i+1;
	END WHILE;
	RETURN i;
END;

SELECT mock_data() -- 执行此函数 生成一百万条数据​

SELECT * FROM app_user WHERE `name`=\'用户99999\' --  1.175 sec

EXPLAIN SELECT * FROM app_user WHERE `name`=\'用户99999\' 

--  2.创建索引的另一种方式 : create index 索引名 on 表名(字段名)


CREATE INDEX id_app_user ON app_user(`name`) --  普通索引

SELECT * FROM app_user WHERE `name`=\'用户99999\' --  0.035 sec

EXPLAIN SELECT * FROM app_user WHERE `name`=\'用户99999\' 

\"在这里插入图片描述\"

\"在这里插入图片描述\"

在数据还是少量的时候,索引的用处不大,在大数据的情况下,索引能够加快查询速度。

7.3 索引原则

  • 索引不是越多越好
  • 不要对进程变动数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在常用来查询的字段上

索引的数据结构

Hash类型的索引

Btree:InnoDB默认的

参考博客:CodingLabs - MySQL索引背后的数据结构及算法原理

8.权限管理和备份

8.1用户管理

SQLyog可视化管理

\"MySQL(狂神说笔记)_第5张图片\"

SQL 命令


-- 创建用户CREATE USER 用户名 IDENTIFIED BY \'密码\'
CREATE USER kuangshen IDENTIFIED BY \'123456\'

-- 修改密码(修改当前用户密码)
SET PASSWORD = PASSWORD(\'123456\')

-- 修改密码(修改指定用户密码)
SET PASSWORD FOR kuangshen = PASSWORD(\'123456\')

-- 重命名 RENAME USER 原名字 TO 新名字
RENAME USER kuangshen TO kuangshen2

--  用户授权ALL PRIVILEGES  全部的权限,库.表
-- ALL PRIVILEGES  除了给别人授权,其他都能干
GRANT ALL PRIVILEGES ON *.* TO kuangshen2

-- 查询权限
SHOW GRANTS FOR kuangshen2
SHOW GRANTS FOR root@localhost

-- root 用户权限:GRANT ALL PRIVILEGES ON *.* TO \'root\'@\'localhost\' WITH GRANT OPTION

-- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM kuangshen2

-- 删除用户
DROP USER kuangshen2

8.2MySQL备份

为什么要备份?

  • 保证数据不丢失
  • 数据转移

MySQL数据库备份的方式

  • 直接拷贝物理文件
  • 在SQLyog这种可视化工具中手动导入
    • 在想要导出的表和库中,右键,选择备份或导出
  • 使用SQL命令行 mysqldump导出
#mysqldump -h 主机 -u 用户名 -p 密码 数据库名 表名 >导出位置
mysqldump -hlocalhost -uroot -p123456 myschool student >D:/a.sql

#mysqldump -h 主机 -u 用户名 -p 密码 数据库名 表1 表2 表3 >导出位置
mysqldump -hlocalhost -uroot -p123456 myschool student result >D:/b.sql

#mysqldump -h 主机 -u 用户名 -p 密码 数据库名 >导出位置
mysqldump -hlocalhost -uroot -p123456 myschool  >D:/c.sql

#导入
#在登陆的情况下,切换到指定的数据库
#source 备份文件
source D:/a.sql

#没有登陆的情况下
mysql -u用户名 -p密码 库名<备份文件

9.规范数据库设计

当数据库比较复杂的时候,我们就需要设计

糟糕的数据库设计:

  • 数据冗余,浪费空间
  • 数据库插入和删除都会麻烦,异常[屏蔽使用物理外键]
  • 程序的性能差

良好的数据库设计:

  • 节省内存空间
  • 保证数据库的完整性
  • 方便我们开发系统

软件开发中,关于数据库的设计:

  • 分析需求:分析业务和需要处理的数据库的需求
  • 概要设计:设计关系图E-R图

设计数据库的步骤:(个人博客)

  • 收集信息,分析需求
    • 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 评论表
    • 友链表(友链信息)
    • 自定义表(系统信息,某个关键的字,或者一些著字段)key:value
    • 说说表(发表心情 id… content…create_time)
  • 标识实体(把需求落地到每一个字段)
  • 标识实体之间的关系
    • 写博客:user --> blog
    • 创建分类:user -->category
    • 关注:user -->user
    • 友链:links
    • 评论:user -->user–>blog

9.2 三大范式

为什么需要数据规范化?

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正常显示信息
  • 删除异常
    • 丢失有效的信息

三大范式(了解)

第一范式

要求数据库的每一列都是不可再分的原子项

第二范式

前提:满足第一范式

每一张表只描述一件事情

第三范式

前提:满足第一范式和第二范式

第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

(规范数据库的设计)

规范性和性能的问题

关联查询的表不能超过三张表

  • 考虑商业化的需求和目标(成本和用户体验)数据库的性能更加重要
  • 在规范性能的问题的时候,需要适当的考虑一下规范性!
  • 故意给某些表增加一些冗余的字段。(从多表查询变为单表查询)
  • 故意增加一些计算列(从大数据量降低为小数据量的查询:索引)

10.JDBC(重点)

10.1 数据库驱动

驱动:声卡,显卡,数据库

\"MySQL(狂神说笔记)_第6张图片\"

我们的程序会通过数据库驱动和数据库打交道。

10.2 JDBC

sun公司为了简化开发人员的(对数据库的统一)操作,提供了一个(java操作数据库的)规范,俗称JDBC。

这些规范的实现有具体的产商去做。

对于开发人员来说,我们只需要掌握JDBC接口的操作即可!

\"MySQL(狂神说笔记)_第7张图片\"

java.sql

javax.sql

还需要导入一个一个数据库驱动包。mysql-connector-java-5.1.47

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(3,\'zhansan\',\'123456\',\'zs@sina.com\',\'1980-12-04\'),
(2,\'lisi\',\'123456\',\'lisi@sina.com\',\'1981-12-04\'),
(3,\'wangwu\',\'123456\',\'wwu@sina.com\',\'1979-12-04\')

1.创建一个普通项目

2.导入数据库驱动

在项目目录下建一个lib目录,再导入jar包,然后右键操作。

3.编写测试代码

package study;

import java.sql.*;

public class JdbcFirstDemo {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        //1.加载驱动
        Class.forName(\"com.mysql.jdbc.Driver\");


        //2.获得用户信息和密码
        String url = \"jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true\";
        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语句获得结果集
        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(\"birth=\" + resultSet.getObject(\"birthday\"));
            System.out.println(\"=====================\");

        }
        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();

    }
}

DriverManager

//1.加载驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName(\"com.mysql.jdbc.Driver\"); // 固定写法,加载驱动

Connection connection = DriverManager.getConnection(url, username, password);
// connection 代表数据库
// 数据库提交
//数据库回滚
// 数据库自动提交
connection.commit();
connection.rollback();
connection.setAutoCommit();

URL

String url = \"jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true\";

// 协议://主机地址:端口号/数据库名?参数1&参数2&参数3

// Oralce  -- 1521
// jdbc:oracle:thin:@localhost:1521:sid
statement   执行SQL的对象

connection.prepareStatement()

statement.executeQuery();// 执行的是查询语句
       statement.execute();// 可以执行任意的SQL语句 效率较低
       statement.executeUpdate(); // 执行的是 更新,插入,删除

resultSet 是一个结果集,里面封装了全部的结果。

resultSet.getObject() // 不知道列类型的情况下使用
// 知道列类型的情况下 使用特定的 
resultSet.getString()
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();

遍历:指针

resultSet.beforeFirst();// 移动到最前面
resultSet.afterLast();// 移动到最后面
resultSet.previous();// 移到前一行
resultSet.next(); // 移动到后面一行
resultSet.absolute(row); // 移动到指定行

释放资源

//6.释放连接
resultSet.close();
statement.close();
connection.close();//很耗资源

10.4 statement对象

jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

Statement对象的executeUpdate方法,用于向数据库发送增,删,改,查的SQL语句,executeUpdate执行完毕后,将会返回一个整数(即增删改查语句导致了数据库几行数据发生了改变)。

Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。

CRUD操作-create

使用executeUpdate(String sql)方法完成数据添加操作,实例操作:

 Statement st = connection.createStatement();

String sql = \"INSERT INTO 表名 (`字段名1`,`字段名2`,`字段名3`) VALUES(`值1`),(\'值2\').... \";

int num = st.executeUpdate(sql);
        
if(num > 0){
    System.out.println(\"添加成功!\");
}

CRUD操作-delete

使用executeUpdate(String sql)方法完成数据删除操作,实例操作:

Statement st = connection.createStatement();

String sql = \"DELETE FROM `student` WHERE `id`=1 \";

int num = st.executeUpdate(sql);

if(num > 0){
    System.out.println(\"删除成功!\");
}

CRUD操作-update

使用executeUpdate(String sql)方法完成数据更新操作,实例操作:

Statement st = connection.createStatement();

String sql = \"UPDATE 表名 SET column_name=value,[column_name=value] WHERE column_name=特定的值\";

int num = st.executeUpdate(sql);

if(num > 0){
    System.out.println(\"删除成功!\");
}

CRUD操作-Query

使用executeQuery(String sql)方法完成数据查询操作,实例操作:

//4.获得执行sql语句的对象  statement 代表sql对象
Statement statement = connection.createStatement();



//5.执行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(\"birth=\" + resultSet.getObject(\"birthday\"));
   System.out.println(\"=====================\");

}

1.提取工具类

package study01;

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 pwd = 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\");
            pwd = properties.getProperty(\"password\");

            Class.forName(driver);//驱动只需要加载一次

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,pwd);
    }

    //释放连接  参数是调用者进行传参
    public static void release(Connection conn, Statement st, ResultSet rt){

            if(rt != null){
                try {
                    rt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }

            if(st != null){
                try {
                    st.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn != null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }


}

  1. executeUpdate 测试增删改
package study;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcDemo02 {

    public static void main(String[] args) {
        Connection connection = null;
        Statement st = null;
        ResultSet rt = null;

        try {
            connection = JdbcUtils.getConnection();// 获取连接
            st = connection.createStatement();//获取SQL对象

            String sql = \"INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)\" +
                    \"VALUES(4,\'mazi\',\'456728\',\'zs@sina.com\',\'1989-11-14\')\";

            int num = st.executeUpdate(sql);

            if(num > 0){
                System.out.println(\"插入成功!\");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,st,rt);//释放资源
        }

    }
}

package study;

import study01.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 connection = null;
        Statement st = null;
        ResultSet rt = null;

        try {
            connection = JdbcUtils.getConnection();// 获取连接
            st = connection.createStatement();//获取SQL对象

            String sql = \"DELETE FROM users WHERE `id` = 4\";

            int num = st.executeUpdate(sql);

            if(num > 0){
                System.out.println(\"删除成功!\");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,st,rt);//释放资源
        }

    }
}

package study;

import study01.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 connection = null;
        Statement st = null;
        ResultSet rt = null;

        try {
            connection = JdbcUtils.getConnection();// 获取连接
            st = connection.createStatement();//获取SQL对象

            String sql = \"UPDATE users SET `name` = \'kuangshen\' where `id` = 1\";

            int num = st.executeUpdate(sql);

            if(num > 0){
                System.out.println(\"更新成功!\");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,st,rt);//释放资源
        }

    }
}

3.executeQuery 实现查询

package study;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestQuery {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rt = null;


        try {
            conn = JdbcUtils.getConnection();

            st = conn.createStatement();

            String sql = \"SELECT * FROM users\";

            rt = st.executeQuery(sql);

            while(rt.next()){
                System.out.println(rt.getInt(\"id\"));
                System.out.println(rt.getString(\"NAME\"));
                System.out.println(rt.getString(\"PASSWORD\"));
                System.out.println(rt.getString(\"email\"));
                System.out.println(rt.getDate(\"birthday\"));
                System.out.println(\"====================\");
            }


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rt);
        }


    }
}

SQl注入问题

SQL存在漏洞,会导致数据泄露 本质就是or导致的

package study;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Test03 {
    public static void main(String[] args) {
        //login(\"kuangshen\",\"123456\");  登陆成功

        login(\"\' or \'1=1\",\"\' or \'1=1\");//SQL注入导致
        /*
        kuangshen
        123456
        ====================
        zhangsan
        123456
        ====================
        lisi
        123456
        ====================
         */
    }

    public static void login(String username,String pwd){
        Connection conn = null;
        Statement st = null;
        ResultSet rt = null;


        try {
            conn = JdbcUtils.getConnection();

            st = conn.createStatement();

            //SELECT * FROM users WHERE `NAME` = \'kuangshen\' AND `PASSWORD` = \'123456\'
            //SELECT * FROM users WHERE `NAME` = \'\' or \'1=1\' AND `PASSWORD` = \'\' or \'1=1\'  
            String sql = \"SELECT * FROM users WHERE `NAME` = \'\"+ username +\"\' AND `PASSWORD` = \'\"+ pwd +\"\'\";

            rt = st.executeQuery(sql);

            while(rt.next()){

                System.out.println(rt.getString(\"NAME\"));
                System.out.println(rt.getString(\"PASSWORD\"));

                System.out.println(\"====================\");
            }


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rt);
        }

    }
}

10.5 PreparedStatement对象

PreparedStatement可以防止SQL注入,效率更高。

1.增删改

package study02;

import study01.JdbcUtils;

import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Test01 {
    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,\"狂生\");
            st.setString(3,\"234516\");
            st.setString(4,\"23457125@qq.com\");
            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);
        }

    }
}

package study02;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class Test02 {
    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);
        }

    }
}
package study02;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Test03 {
    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,\"狂生\");
            st.setInt(2,1);//填入参数

            int i = st.executeUpdate();//执行

            if (i > 0) {
                System.out.println(\"更新成功\");
            }


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.release(conn, st, null);
        }

    }
}

2.查询

package study02;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Test04 {

    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);

            st.setInt(1,1);

            rs = st.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt(\"id\"));
                System.out.println(rs.getString(\"NAME\"));
                System.out.println(rs.getString(\"PASSWORD\"));
                System.out.println(rs.getString(\"email\"));
                System.out.println(rs.getDate(\"birthday\"));
                System.out.println(\"=====================\");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

    }

}

3.防止SQL注入

本质是 将输入的参数看作是字符

然后含有转义字符的,自动过滤。

package study02;

import study01.JdbcUtils;

import java.sql.*;

public class Test05 {
    public static void main(String[] args) {
        //login(\"lisi\",\"123456\");  //登陆成功

        login(\"\' or \'1=1\",\"\' or \'1=1\");//SQL注入导致

    }

    public static void login(String username,String pwd){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rt = null;


        try {
            conn = JdbcUtils.getConnection();



            //SELECT * FROM users WHERE `NAME` = \'kuangshen\' AND `PASSWORD` = \'123456\'
            //SELECT * FROM users WHERE `NAME` = \'\' or \'1=1\' AND `PASSWORD` = \'\' or \'1=1\'
            String sql = \"SELECT * FROM users WHERE `NAME` = ? AND `PASSWORD` = ?\";

            st = conn.prepareStatement(sql);

            st.setString(1,username);
            st.setString(2,pwd);

            rt = st.executeQuery();

            while(rt.next()){

                System.out.println(rt.getString(\"NAME\"));
                System.out.println(rt.getString(\"PASSWORD\"));

                System.out.println(\"====================\");
            }


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rt);
        }

    }
}

10.6 使用IDEA连接数据库

连接数据库

\"MySQL(狂神说笔记)_第8张图片\"

连接成功后,选择数据库

\"MySQL(狂神说笔记)_第9张图片\"

双击数据库查看数据

\"MySQL(狂神说笔记)_第10张图片\"

更新数据

\"MySQL(狂神说笔记)_第11张图片\"

\"MySQL(狂神说笔记)_第12张图片\"

连接失败,查看原因

\"MySQL(狂神说笔记)_第13张图片\"

10.7事务

要么成功,要么失败。

将一个 SQL 放在一个批次去执行。

事务原则:ACID原则 原子性 一致性 持久性 隔离性 脏读 不可重复读 幻读

原子性

要么都成功,要么都失败。

一致性

事务前后的完整性要保证一致 比如转钱前后的钱总数一致

隔离性

事务的隔离性是多个用户并发的访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,事物之间要相互隔离。

持久性

事务一旦提交,那么就会被持久化到数据库。

脏读:

指一个事务读取了另外一个事务未提交的数据。

不可重复读:

在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

幻读:

是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

代码实现

1.关闭自动提交 ,并自动开启事务。conn.setAutoCommit(false);

2.提交数据至数据库 conn.commit();

3.如果失败则回滚 conn.rollback();

package study;

import study01.JdbcUtils;

import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();//连接数据库

            conn.setAutoCommit(false);// 关闭自动提交 ,并开启事务

            st = conn.createStatement();

            String sql1 = \"update account set `money` = `money` - 100 where `NAME`=\'A\'\";
            st.executeUpdate(sql1);

            String sql2 = \"update account set `money` = `money` + 100 where `NAME`=\'B\'\";
            st.executeUpdate(sql2);

            conn.commit();// 提交数据至数据库
            System.out.println(\"成功\");

        } catch (SQLException throwables) {

            try {//如果失败,则进行回滚
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }


    }
}

10.8 数据库连接池

数据库连接 — 执行完毕 — 释放

连接 – 释放 十分浪费资源

池化技术:准备一些预先的资源,过来就连接预先准备好的。

------- 开门–业务员 : 等待 – 服务 —

常用连接数 10个

最小连接数 : 10

最大连接数 :15 业务最高承载上限

排队等待

等待超时:100ms

编写连接池,实现一个接口 DataSource

开源数据源实现

DBCP

C3P0

Druid : 阿里巴巴

使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库代码。

DBCP

需要用到的jar包

commons-dbcp-1.4 commons-pool-1.6

C3P0

需要用到的jar包

c3p0-0.9.5.5 mchange-commons-java-0.2.19

结论

无论使用什么数据源,本质还是一样的,DataSource接口不变,方法就不会变。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号