mysql

windows安装mysql5.7

(1) 在D:\MySQL5.7\mysql-5.7.25-winx64文件下创建一个my.ini文件
以下部分可以黏贴: 但是要注意路径,除非你和我的一模一样.
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[mysqld]
# 设置3306端口
port = 3306
# 设置mysql的安装目录
basedir=D:\MySQL5.7\mysql-5.7.25-winx64
# 设置mysql数据库的数据的存放目录
datadir=D:\MySQL5.7\mysql-5.7.25-winx64\data
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB


以管理员身份运行cmd,进入bin目录,执行:
(2)初始化,创建mysql默认的root账户
mysqld --initialize-insecure --user=mysql 命令。不进行这一步,安装完成之后无法启动服务。
(3)依然在管理员cmd窗口的bin目录下,执行 mysqld install  命令安装。完成后会提示安装成功。
(4)依然在管理员cmd窗口的bin目录下,执行 net start mysql 命令启动MySQL服务。
(5)修改环境变量,添加"D:\MySQL5.7\mysql-5.7.25-winx64\bin"。
(6)cmd窗口中,执行 mysql -uroot -p 命令,默认没有密码,回车进入
(7)若要卸载,需要先停止服务,再删除即可

# 启动mysql服务
net start mysql
# 停止mysql服务
net stop mysql 
# 重启:先停止在启动

mysql

#使用方法:
	方式一: 通过图型界面工具,如 Navicat 等( 高级课使用 )
	方式二: 通过在命令行敲命令来操作 ( 基础阶段使用 )


#SQL ( Structure query language ) 结构化查询语言
SQL语言分为4个部分:DDL(定义)、DML(操作)、DQL(查询)、DCL(控制)
	1、DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER
	2、DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
	3、DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE
	4、DQL语句 数据库操纵语言:查询数据SELECT

#mysql数据库管理软件,记录事物一些数据特征:
	由库,表,记录组成.
	库相当于一个文件夹
	表相当于一个文件
	记录就是文件里面一条一条的内容
	表中的成员属性就是一个一个字段
	可以为每个项目建立一个数据库

#关系型数据库:表与表之间有联系
比如:mysql,oracle,db2,sqlserver

#非关系型数据库: key-value 键值对形式 没有表的概念
比如:redis,mongodb,memcache



cmd中:
	命令可以用tab来补全
	d:  可以直接切换路径
	D:dir 可以查看文件夹中的内容
	
	cls 清屏(windows)  ctrl + 1 清屏(linux)
	ctrl+c 终止

[windows] 在超级管理员权限下才能使用
	net start mtsql  启动mtsql
	net stop mysql   停止mysql

[linux]
	service mysql start    启动mysql
	service mysql stop 	   停止mysql
	service mysql restart  重启mysql

mysql part1 基本指令

登陆完整语法:
	mysql -u用户名 -p密码 -h地址ip

#登陆到本地mysql 默认用户root 是最高权限账户
mysql -uroot -p
localhost => 127.0.0.1 本地ip地址

#退出mysql 
\q 或者 exit

#远程连接mysql 服务器
mysql -uroot -p -h192.168.31.156

mysql part2 基本指令

#查看连接用户
select user()
	+---------------+
	| user()        |
	+---------------+
	| zzz@localhost |
	+---------------+
	1 row in set (0.00 sec)

#设置密码
set password = password("111");

#去除密码
set password = password("");

#concat 拼接
select concat(参数1 , 参数2 , 参数3...) 
把所有的参数拼接在一起,中间可以放置符号来分割
例如 : select concat(c,":",v,":",t) from t7;

mysql part3 权限

ipconfig (windows)  |  ifconfig (linux)

#windows 连接远程linux中的mysql
create user "ceshi"@"ip" identified by "密码";
#给具体某个网段下的所有ip设置账户 % 代表任意数据0~255
create user "ceshi"@"192.168.31.%" identified by "密码";
#给所有ip都可以登陆 % 任意所有ip
create user "ceshi"@"%" identified by "密码"

#USAGE 没有任何权限
	mysql> show grants for "zzz"@"%";
	+---------------------------------+
	| Grants for zzz@%                |
	+---------------------------------+
	| GRANT USAGE ON *.* TO 'zzz'@'%' |
	+---------------------------------+
	1 row in set (0.00 sec)
grant 权限 on 数据库.表名 to "用户名"@"ip" identified by "密码"

主要权限:
	select  查询数据库的权限
	insert  插入数据库的权限
	update  更新数据库的权限
	delete  删除数据库的权限
	* 代表所有
	
	
#赋予查询数据库的权限
grant select on *.* to "zzz"@"%" identified by "111";
#all  代表所有权限
grant all on *.* to "zzz"@"%" identified by "111";
#查看所有数据库
show databases;
#移除权限
revoke delete on *.* from "zzz"@"%";
#删除账户
drop user "zzz"@"%";
#刷新权限 , 立刻生效
flush privileges;

mysql part4 [重点] 增删改查

#操作[数据库](文件夹)
	
	增
	#创建数据库
	create database db1 charset utf8;

	查
	#查看所有数据库
	show databases;
	#查看数据库的建表语句
	show create database db1;
	+----------+--------------------------------------------------------------+
	| Database | Create Database                                              |
	+----------+--------------------------------------------------------------+
	| db1      | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8 */ |
	+----------+--------------------------------------------------------------+
	1 row in set (0.00 sec)

	改
	#alter 更改数据库的字符集
	alter database db1 charset gbk;
	+----------+-------------------------------------------------------------+
	| Database | Create Database                                             |
	+----------+-------------------------------------------------------------+
	| db1      | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET gbk */ |
	+----------+-------------------------------------------------------------+
	1 row in set (0.00 sec)

	删
	#删除数据库db1
	drop database db1;



#操作[数据表] (文件)
	选择数据库
		use 数据库名
		use db2
	
	增
	#int 整型  char 字符
	#字段名1 ,类型1 , 字段名2 ,类型2
	create table z1(id int , name char);

	查
	#查询所有数据表
	show tables;
	#查看表的建表语句
	show create table z1\G	(#\G是垂直显示,默认横向)
	*************************** 1. row ***************************
			   Table: z1
		Create Table: CREATE TABLE `z1` (
		  `id` int(11) DEFAULT NULL,
		  `name` char(1) DEFAULT NULL
		) ENGINE=InnoDB DEFAULT CHARSET=utf8
		1 row in set (0.00 sec)
	#查看表结构
	desc z1;
	+-------+---------+------+-----+---------+-------+
	| Field | Type    | Null | Key | Default | Extra |
	+-------+---------+------+-----+---------+-------+
	| id    | int(11) | YES  |     | NULL    |       |
	| name  | char(1) | YES  |     | NULL    |       |
	+-------+---------+------+-----+---------+-------+
	2 rows in set (0.00 sec)

	改
	#modify 只能改变数据类型
	alter table z1 modify name chat(3);#int(3);
	#change 连字段名+数据类型一起改变
	alter table z1 change name NAME char(1);
	#add 添加字段
	alter table z1 add age char(2);
	#drop 删除字段 column列(字段,关键字)
	alter table z1 drop column NAME;
	#rename 更改表名
	alter table z1 rename z2;


	删
	#删除表z2
	drop table z2;



#操作记录 (文件中的数据)
	mysql null 相当于 python None 是一样的 代表空 什么都没有

	增
	#一次插入一条数据
	insert into 表名(字段1 , 字段2... ) values(值1.值2)
	insert into z1(id , name ) values(1,"name");
	#一次插入多条数据
	insert into z1(id , name ) values(2,"xker"),(3,"cker");
	#不指定具体字段,默认把所有字段值插一遍
	insert into z1 values(4,"qker");
	#可以具体指定某个字段进行插入
	insert into z1(name) values("wker");

	查
	# * 代表所有
	select * from z1;
	#把要搜索的字段写在select后面
	select id,name from z1;

	改
	#update 表名 set 字段=值 where 条件
	updata z1 set name="zzker" where id = 1;
	#如果不加条件  所有数据都会改掉
	update z1 set name="zker";

	删
	#删除id为2 的这条数据
	delete from z1 where id=1;
	#清空
	delete from z1;
	#重置数据表(重置id)
	truncate table z1;

mysql part5 常用数据类型

常用数据类型

#整型
tinyint 1个字节 有符号(-128~127) 无符号(unsigned)(0~255)小整型值
int     4个字节 有符号(-21亿~21亿 左右)  无符号(0~42亿左右) 大整型值

create table z2(id int , age tinyint);
insert into z2(id,age) values(4200000000,255);#error
insert into z2(id,age) values (2100000000,127);#bingo



#浮点型
float(255,30)   单精度
double(255,30)  双精度
decimal(65,30)  金钱类型,使用字符串的形式保存小数

存在四舍五入
	create table z3(f1 float(5,2),f2 double(5,2),f3 decimal(5,2));
	insert into z3 values (1.1111111,1.555555555555,1.33333333333);
	+------+------+------+
	| f1   | f2   | f3   |
	+------+------+------+
	| 1.11 | 1.56 | 1.33 |
	+------+------+------+
	1 row in set (0.00 sec)


float小数默认保留5位, double 16位 , decimal保留整数位,存在四舍五入
	create table z4(f1 float , f2 double ,f3 decimal);
	insert into z4 values(1.6666666666666666666,1.6666666666666666666666,1.6666666666666666666);
	+---------+--------------------+------+
	| f1      | f2                 | f3   |
	+---------+--------------------+------+
	| 1.66667 | 1.6666666666666667 |    2 |
	+---------+--------------------+------+
	1 row in set (0.00 sec)


float(5,2) 5代表总长度(整数+小数) 2=> 小数长度,保留2位




#字符串 char(字符长度)  varchar(字符串) text
char(11)      定长:固定开辟11个字符长度的空间(手机号,身份证号) , 开辟空间更快   范围:255字符长度
varchar(11)   变长:最多创建字符长度位11的空间(小广告,评论) 开辟空间不如char快    范围 : 21845字符长度
text          文本类型,针对于文章,小说

create table z5(c char(11),v varchar(11),t text);
insert into z5 values ("12345678901","一二三四五六七八九十一","ohhhhhhhhhhhhhhhhhh");
select concat(c,":",v,":",t) from z5;



#枚举和集合
	enum 枚举 : 从列出来的数据中选一个(例如性别)
	set  集合 : 从列出来的数据中选多个(自动去重)
	create table z6(id int ,name char(5),sex enum("man","woman"), money float(5,2),hobby set("madelove"))
	insert table z6 values(1,"zker","woman",999.991,"madelove,madelove,madelove")
		+------+------+-------+--------+----------+
		| id   | name | sex   | money  | hobby    |
		+------+------+-------+--------+----------+
		|    1 | zker | woman | 999.99 | madelove |
		+------+------+-------+--------+----------+
		1 row in set (0.00 sec)



#时间
	#在输入时间时,要注意时间日期是否过期
	date  YYYY-MM-DD 年月日 (结婚纪念日,节假日)
	time  HH:MM:SS   时分秒 (体育竞赛)
	year  YYYY       年份值 (历史)
	datetime  YYYY-MM-DD HH:MM:SS  年月日 时分秒 (登陆时间)

	create table z1(d date , t time , y year , dt datetime);
	
	insert into z1 values("2020-05-13","01-01-01","1997","2020-05-13 20:20:20");
	+------------+----------+------+---------------------+
	| d          | t        | y    | dt                  |
	+------------+----------+------+---------------------+
	| 2020-05-13 | 01:01:01 | 1997 | 2020-05-13 20:20:20 |
	+------------+----------+------+---------------------+
	1 row in set (0.00 sec)


	#mysql 内置函数
		now 获取当前时间  select now()
	insert into z1 values(now(),now(),now(),now());
	+------------+----------+------+---------------------+
	| d          | t        | y    | dt                  |
	+------------+----------+------+---------------------+
	| 2020-06-17 | 20:37:17 | 2020 | 2020-06-17 20:37:17 |
	+------------+----------+------+---------------------+
	1 row in set (0.00 sec)


	#timestamp YYYYMMDDHHMMSS (时间戳) 
	自动更新时间(不需要手动写入,修改数据时自动更新,记录最后一次修改的时间)
	
	create table z1(dt datetime , ts timestamp);
	
	insert into z1 values(null,null);
		+------+---------------------+
		| dt   | ts                  |
		+------+---------------------+
		| NULL | 2020-06-17 20:41:48 |
		+------+---------------------+
		1 row in set (0.00 sec)

	insert into z1 values(199705130015010101,20200202010101);
		+---------------------+---------------------+
		| dt                  | ts                  |
		+---------------------+---------------------+
		| 1997-05-13 01:01:01 | 2020-02-02 01:01:01 |
		+---------------------+---------------------+
		1 row in set (0.00 sec)

mysql 约束

[创建表: 字段 类型 约束 ...]
对编辑的数据进行类型限制,不满足约束条件的直接报错



#unsigned  无符号
	
	create table z1(id int unsigned);
	insert into z1 values(4200000000);
	+------------+
	| id         |
	+------------+
	| 4200000000 |
	+------------+
	在int 无符号情况下 最大范围42亿


#not null  不为空

	create table z2(id int not null, name char(255));
	insert into z2 values(null,"zker");	#error
	insert into z2 values(1,null);
	+----+------+
	| id | name |
	+----+------+
	|  1 | NULL |
	+----+------+


#default  设置默认值
	
	create table z3(id int not null , name char(5) default "zker");
	insert into z3 values(1,null);	#可以塞入null , 不使用默认值
	insert into z3(id) values (2); 	#什么都不塞入值使用默认值
	+----+------+
	| id | name |
	+----+------+
	|  1 | NULL |
	|  2 | zker |
	+----+------+


#unique  唯一约束 , 数据唯一不能重复
	索引 : 相当于字典的目录 , 通过索引可以加快查询速度
	UNI 唯一索引  允许塞null空值

	create table z4(id int unique , name char(5) default "zker");
	insert into z4(id) values(1);
	insert into z4(id) values(1);#error
	insert into z4(id) values(2);
	insert into z4(id) values(null);
	insert into z4(id) values(null);
	insert into z4(id) values(null);
	insert into z4(id) values(null);
	insert into z4(id) values(null);
	+------+------+
	| id   | name |
	+------+------+
	|    1 | zker |
	|    2 | zker |
	| NULL | zker |
	| NULL | zker |
	| NULL | zker |
	| NULL | zker |
	| NULL | zker |
	+------+------+
	+-------+---------+------+-----+---------+-------+
	| Field | Type    | Null | Key | Default | Extra |
	+-------+---------+------+-----+---------+-------+
	| id    | int(11) | YES  | UNI | NULL    |       |
	| name  | char(5) | YES  |     | zker    |       |
	+-------+---------+------+-----+---------+-------+


#primary key   主键,标记数据的唯一特征(唯一且不为空的数据)
	PRI 主键 非空且唯一  在一个表里面 只能有一个字段是主键
	
	create table z5(id int not null unique , name char(5) default("zker")):
	insert into z5 values (null,"aaa");	#error
	insert into z5 values (1,"aaa");
		+-------+---------+------+-----+---------+-------+
		| Field | Type    | Null | Key | Default | Extra |
		+-------+---------+------+-----+---------+-------+
		| id    | int(11) | NO   | PRI | NULL    |       |
		| name  | char(5) | YES  |     | zker    |       |
		+-------+---------+------+-----+---------+-------+
		2 rows in set (0.00 sec)


	#primary key 创建主键
	create table z6(id primary key , name char(5) default "zker");
	insert into z6 values(1,"zzz");
		+-------+---------+------+-----+---------+-------+
		| Field | Type    | Null | Key | Default | Extra |
		+-------+---------+------+-----+---------+-------+
		| id    | int(11) | NO   | PRI | NULL    |       |
		| name  | char(5) | YES  |     | zker    |       |
		+-------+---------+------+-----+---------+-------+


	#两者同时存在(优先显示primary key 作为主键 , 另一个被标记成UNI 唯一索引)
	create table z7(id int primary key , name char(5) not null unique);
		+-------+---------+------+-----+---------+-------+
		| Field | Type    | Null | Key | Default | Extra |
		+-------+---------+------+-----+---------+-------+
		| id    | int(11) | NO   | PRI | NULL    |       |
		| name  | char(5) | NO   | UNI | NULL    |       |
		+-------+---------+------+-----+---------+-------+

	#一个表中只能有一个主键
	create table z8(id int primary key , name char(5) primary key);	#error





#auto_increment 自增加一(一般配合主键使用 或者 unique进行自增)
	create table z1(id int primary key auto_increment , name char(5) default "zker");
	+-------+---------+------+-----+---------+----------------+
	| Field | Type    | Null | Key | Default | Extra          |
	+-------+---------+------+-----+---------+----------------+
	| id    | int(11) | NO   | PRI | NULL    | auto_increment |
	| name  | char(5) | YES  |     | zker    |                |
	+-------+---------+------+-----+---------+----------------+
	2 rows in set (0.00 sec)

	insert into z1 values(1,"zzz");
	insert into z1 values(null,null);
	insert into z1 values(2,null);	#error
	insert into z1 values(3,null);
	insert into z1 values(null,null);
	#使用默认值插入
	insert into z1 values();
		+----+------+
		| id | name |
		+----+------+
		|  1 | zzz  |
		|  2 | NULL |
		|  3 | NULL |
		|  4 | NULL |
		|  5 | zker |
		+----+------+

	#delete单纯的删除数据,数据id号会从上一个继续自增
	delete from z1;
	#truncate 删除所有数据 , id从头开始(重置表)
	truncate table z1;




#zerofill  0填充(配合int类型使用) int(6) 位数不够用0填充
	create table z2(id int(6) zerofill);
	insert into z2 values(1);
		+--------+
		| id     |
		+--------+
		| 000001 |
		+--------+



#联合唯一约束 : unique(字段1,字段2,字段3 ... ) 把多个字段拼在一起表达唯一的数据
	MUL 代表普通索引  UNI  唯一索引   PRI  主键索引
	
	#联合唯一索引 , 都为非空的字段显示PRI , 联合在一起做的主键不是单个字段的主键
	create table z3(id int ,name char(5) not null , ip char(15) not null , port int not null, unique(ip,port));
	insert into z3 values(1,"zzz","127.0.0.1","3333" );
	insert into z3 values(1,"zzz","127.0.0.1","2222" );
	insert into z3 values(1,"zzz","127.1.1.1","3333" );
	insert into z3 values(1,"zzz","127.1.1.1","3333" );
		+------+------+-----------+------+
		| id   | name | ip        | port |
		+------+------+-----------+------+
		|    1 | zzz  | 127.0.0.1 | 2222 |
		|    1 | zzz  | 127.0.0.1 | 3333 |
		|    1 | zzz  | 127.1.1.1 | 3333 |
		+------+------+-----------+------+

		+-------+----------+------+-----+---------+-------+
		| Field | Type     | Null | Key | Default | Extra |
		+-------+----------+------+-----+---------+-------+
		| id    | int(11)  | YES  |     | NULL    |       |
		| name  | char(5)  | NO   |     | NULL    |       |
		| ip    | char(15) | NO   | PRI | NULL    |       |
		| port  | int(11)  | NO   | PRI | NULL    |       |
		+-------+----------+------+-----+---------+-------+

	#联合唯一索引(为空的字段 , 允许插入null, 显示MUL)
	create table z4(id int ,name char(5) not null , ip char(15)  , port int , unique(ip,port));
	insert into z4 values(1,"zzz","127.0.0.1","3333" );
	insert into z4 values(1,"zzz","127.0.0.1","2222" );
	insert into z4 values(1,"zzz","127.1.1.1","3333" );
	insert into z4 values(1,"zzz",null,null );
	insert into z4 values(1,"zzz",null,null );
	insert into z4 values(1,"zzz",null,null );
	insert into z4 values(1,"zzz",null,null );
	可以插入多个空值

		+-------+----------+------+-----+---------+-------+
		| Field | Type     | Null | Key | Default | Extra |
		+-------+----------+------+-----+---------+-------+
		| id    | int(11)  | YES  |     | NULL    |       |
		| name  | char(5)  | NO   |     | NULL    |       |
		| ip    | char(15) | YES  | MUL | NULL    |       |
		| port  | int(11)  | YES  |     | NULL    |       |
		+-------+----------+------+-----+---------+-------+

		+------+------+-----------+------+
		| id   | name | ip        | port |
		+------+------+-----------+------+
		|    1 | zzz  | 127.0.0.1 | 3333 |
		|    1 | zzz  | 127.0.0.1 | 2222 |
		|    1 | zzz  | 127.1.1.1 | 3333 |
		|    1 | zzz  | NULL      | NULL |
		|    1 | zzz  | NULL      | NULL |
		|    1 | zzz  | NULL      | NULL |
		|    1 | zzz  | NULL      | NULL |
		+------+------+-----------+------+



	#联合唯一索引和主键可以同时存在
		primary key是真正的主键
		联合唯一索引变成MUL
		一个是PRI 一个是MUL
		create table z5(id int ,name char(5) not null , ip char(15)  , port int , unique(ip,port));
		alter table z5 add primary key(id);
			+-------+----------+------+-----+---------+-------+
			| Field | Type     | Null | Key | Default | Extra |
			+-------+----------+------+-----+---------+-------+
			| id    | int(11)  | NO   | PRI | NULL    |       |
			| name  | char(5)  | NO   |     | NULL    |       |
			| ip    | char(15) | YES  | MUL | NULL    |       |
			| port  | int(11)  | YES  |     | NULL    |       |
			+-------+----------+------+-----+---------+-------+

		unique(ip,port) 联合唯一索引
		primary key(ip,port) 联合唯一主键
		这两个用法一样,区别在于 : 
			前者可以继续添加一个主键 而后者不能继续添加主键
			主键只能是单个字段 , 或者联合主键 , 如果再添加主键就会报错




#foreign key  外键,把多张表通过一个关联字段,联合在一起
	外键的要求 : 要求关联的字段必须具有唯一属性(unique或者primary key)

	student
	id   name       age  classname  address
	1    wangzhen   80   python30   北京市天安门阁楼里
	2    xiaolin    90   python30   东北老革命工业基地
	3    wangwen    18   python31   内蒙古呼和浩特蒙古包

	# 为了避免出现过多的字段,可以采用分表的形式,来提升效率,减少数据的冗余

	student1
		id  name      age  address               classid
		1   wangzhen  80   北京市天安门阁楼里    1
		2   xiaolin   90   东北老革命工业基地    1
		3    wangwen  18   内蒙古呼和浩特蒙古包  2
		
	class1:
		id  classname  datetime
		1   python30   2020-01-01 09:09:09
		2   python31   2020-02-01 09:09:09


	#创建class1 表
	create table class1(id int ,classname varchar(255));
	#被关联的字段至少需要具有唯一属性
	alter table class1 add unique(id);
	
	+-----------+--------------+------+-----+---------+-------+
	| Field     | Type         | Null | Key | Default | Extra |
	+-----------+--------------+------+-----+---------+-------+
	| id        | int(11)      | YES  | UNI | NULL    |       |
	| classname | varchar(255) | YES  |     | NULL    |       |
	+-----------+--------------+------+-----+---------+-------+
	
	#创建student1 学生表
	create table student1(
	id int primary key auto_increment,
	name varchar(255) not null,
	age int not null,
	classid int,
	foreign key(classid) references class1(id)
	);
	+---------+--------------+------+-----+---------+----------------+
	| Field   | Type         | Null | Key | Default | Extra          |
	+---------+--------------+------+-----+---------+----------------+
	| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
	| name    | varchar(255) | NO   |     | NULL    |                |
	| age     | int(11)      | NO   |     | NULL    |                |
	| classid | int(11)      | YES  | MUL | NULL    |                |
	+---------+--------------+------+-----+---------+----------------+

	insert into class1 values(1,"python30");
	insert into class1 values(2,"python31");
	insert into student1 values(null,"zker",18,1);
	insert into student1 values(null,"xker",19,2);
	insert into student1 values(null,"cker",20,1);


		+------+-----------+
		| id   | classname |
		+------+-----------+
		|    1 | python30  |
		|    2 | python31  |
		+------+-----------+


		+----+------+-----+---------+
		| id | name | age | classid |
		+----+------+-----+---------+
		|  1 | zker |  18 |       1 |
		|  2 | xker |  19 |       2 |
		|  3 | cker |  20 |       1 |
		+----+------+-----+---------+

	#删除class1 如果这条数据在其他表里存在,直接删会报错,因为外键的关联限制
	delete from class1 where id = 1;	#error

	#先把关联的数据删除之后,才可以真正删掉这条数据
	delete from student1 where id = 1;
	delete from class1 where id = 1;



	#联级删除 联级更新 (谨慎操作)
		联级删除 on delete cascade
		联级更新 on update cascade
	
		#创建class2
		create table class2(id int unique , classname varchar(255));
		#创建student2
		create table student2(
		id int primary key auto_increment,
		name varchar(255) not null,
		age int not null,
		classid int,
		foreign key(classid) references class2(id) on delete cascade on update cascade
		);

		insert into class2 values(1,"python30");
		insert into class2 values(2,"python31");
		insert into student2 values(null,"wangzhen",80,2);
		insert into student2 values(null,"xiaolin", 90,1);
		insert into student2 values(null,"wangwen", 18,2);
			+------+-----------+
			| id   | classname |
			+------+-----------+
			|    1 | python30  |
			|    2 | python31  |
			+------+-----------+

			+----+----------+-----+---------+
			| id | name     | age | classid |
			+----+----------+-----+---------+
			|  1 | wangzhen |  80 |       2 |
			|  2 | xiaolin  |  90 |       1 |
			|  3 | wangwen  |  18 |       2 |
			+----+----------+-----+---------+

			+-----------+--------------+------+-----+---------+-------+
			| Field     | Type         | Null | Key | Default | Extra |
			+-----------+--------------+------+-----+---------+-------+
			| id        | int(11)      | YES  | UNI | NULL    |       |
			| classname | varchar(255) | YES  |     | NULL    |       |
			+-----------+--------------+------+-----+---------+-------+

			+---------+--------------+------+-----+---------+----------------+
			| Field   | Type         | Null | Key | Default | Extra          |
			+---------+--------------+------+-----+---------+----------------+
			| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
			| name    | varchar(255) | NO   |     | NULL    |                |
			| age     | int(11)      | NO   |     | NULL    |                |
			| classid | int(11)      | YES  | MUL | NULL    |                |
			+---------+--------------+------+-----+---------+----------------+


		#联级删除
		delete from class2 where id = 2;
			+----+---------+-----+---------+
			| id | name    | age | classid |
			+----+---------+-----+---------+
			|  2 | xiaolin |  90 |       1 |
			+----+---------+-----+---------+

		#联级更新
		update class2 set id =100 where classname = "python30";
			+----+---------+-----+---------+
			| id | name    | age | classid |
			+----+---------+-----+---------+
			|  2 | xiaolin |  90 |     100 |
			+----+---------+-----+---------+

表与表之间的关系

一对一 表1 :  id z1 z2 z3   表2: id z4 z5 z6 关联字段(表1中的id) ...

一对多或者多对一 : 一个班级里可以对应多个学生,把学生作为主动关联的表,设置一个外键,去存储班级表的关联字段中的数据

多对多 : 一个学生可以对应多个学科,一个学科也可以被多个学生学习

	xueke (表1)
	id  name
	1   math
	2   english
	3   wuli

	student (表2)
	id  name
	1   wangwen
	2   weiyilin
	3   wangyingqian
#表达多对多关系时, 需要第三张关系表
	relation (表3)  把xid  和 sid 设置成外键  关联xueke的id  和 student的id

	xid  sid
	1    1
	1    2
	1    3
	2    1
	2    2
	2    3
	3    1
	3    2
	3    3

存储引擎 : 存储数据的结构方式

#查看存储引擎
show engines; 
#查看当前的默认存储引擎:
show variables like "default_storage_engine";
#更改表的存储引擎
alter table t1 engine = innodb;


# 概念理解:
表级锁 : 如果有人修改了当前这个表,会直接上表锁,其他人无法修改,在编辑数据时候,速度慢,不能高并发(MyISAM)
行级锁 : 如果有人修改了当前这个表中的一条记录,当前这个数据记录会上锁,其他数据仍然可以正常修改,速度快,允许更高的并发(InnoDB)
支持事务处理 : 如果执行sql语句,在全部成功之后,在选择提交数据,有一条失败,立刻回滚,恢复成原来状态.
begin :   开始事务
commit :  提交数据
rollback: 回滚数据


InnoDB : 5.6版本后的默认存储引擎,支持事务处理,行级锁,外键
	用于事务处理应用程序,支持外键和行级锁。如果应用对事物的完整性有比较高的要
	求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包括很多更
	新和删除操作,那么InnoDB存储引擎是比较合适的。InnoDB除了有效的降低由删除
	和更新导致的锁定,还可以确保事务的完整提交和回滚,对于类似计费系统或者财务
	系统等对数据准确要求性比较高的系统都是合适的选择。

MyISAM : 5.6版本前的默认存储引擎,支持表级锁
	如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完
	整性、并发性要求不高,那么可以选择这个存储引擎。



MEMORY : 把数据放在内存中,用做缓存
	将所有的数据保存在内存中,在需要快速定位记录和其他类似数据的环境下,可以提
	供极快的访问。Memory的缺陷是对表的大小有限制,虽然数据库因为异常终止的话
	数据可以正常恢复,但是一旦数据库关闭,存储在内存中的数据都会丢失。



BLACKHOLE : 黑洞,用来同步主从数据库中的数据.场景发生在服务器并发集群,用在主从数据库当中[主数据库:增删改,从数据库:查询]





D:\MySQL5.7\mysql-5.7.25-winx64\data\db0617
	create table  myisam1(id int,name char(10)) engine = myisam;
	myisam1.frm 表结构
	myisam1.MYD 表数据
	myisam1.MYI 表索引


	create table  innodb1(id int,name char(10)) engine = innodb;
	innodb1.frm 表结构
	innodb1.ibd 表数据+表索引

	create table  memory1(id int,name char(10)) engine = memory;
	memory1.frm 表结构
	没有表数据文件,因为把数据存放在内存中了.
	
	create table  blackhole1(id int,name char(10)) engine = blackhole;
	blackhole1.frm 表结构

约束的添加和删除

#添加/删除 约束 not null
modify 用来改变数据类型
alter table 表名 modify 字段名 类型
alter table z1 modify id int not null
alter table z1 modify id int


#添加/删除 unique 唯一索引

1、普通索引(index):仅仅是加快查询速度
2、唯一索引(unique index):行上的值不能重复
3、主键索引(primary key):主键不能索引
主键索引必定是唯一的,唯一索引不一定是主键,
一张表上只能一个主键,可以有一个或者多个唯一索引。

alter table 表名 add unique(id)
alter table z1 add unique(id)
alter table z1 drop index id


#添加/删除 primary key
alter table 表名 add primary key(id)
alter table z1 add primary key(id)
alter table z1 drop primary key


#添加/删除 foreign key 外键
(先通过desc表 找到外键名字然后再删)
alter table z1 drop foreign key z1_id_1 
alter table z1 add foreign key(id) references class1(id)

单表查询

#sql 查询语句的完整语法
select .. from .. where .. group by having .. order by .. limit..

#where 条件的使用
	功能: 对表中的数据进行筛选和过滤

	语法: 
		1.判断的符号:
		= > >= < <= (!= <> 不等于)
		2.拼接条件的关键字
		and or not
		3.查询的区间范围值 between
		between 小值 and 大值 [小值,大值] 查询两者之间这个范围内所有数据
		4.查询具体某个值的范围 in
		in(1,2,3)
		5.模糊查询 like "%" "_" 通配符
			like "%a"  匹配以a结尾的任意长度的字符串
			like "a%"  匹配以a开头的任意长度的字符串
			like "%a%" 匹配含有a字母的任意长度的字符串
			like "_a"  个数一共2个字符,必须以a结尾,前面的字符随意
			like "a__" 个数一共3个字符,必须以a开头,后面的字符随意

'''
#创建表
create table employee(
id int not null unique auto_increment,
emp_name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一个部门一个屋子
depart_id int
);


#三个部门:教学,销售,运营
insert into employee(emp_name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龙','male',48,'20101111','teacher',10000,401,1),

('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),

('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬银','female',18,'20130311','operation',19000,403,3),
('程咬铜','male',18,'20150411','operation',18000,403,3),
('程咬铁','female',18,'20140512','operation',17000,403,3)
;'''


#where使用

	#单条件查询
	查询部门是sale的所有员工姓名
	select emp_name from employee where post="sale";
	
	#多条件查询
	部门是teacher , 收入大于10000的所有数据
	select *from employee where post="teacher" and salary > 10000;
	
	#关键字 between .. and ..
	#收入在一万到两万之间的所有员工姓名和收入
	select emp_name,salary from employee where salary between 10000 and 20000;
	#收入不在一万到两万的所有员工姓名和收入
	select emp_name,salary from employee where salary not between 10000 and 20000;

	#null 关键字 在查询的时候 要用is进行判定 , 不要用=
	查询post_comment 是空的所有数据
	select *from employee where post_comment is null;

	#关键字 in 在..之中查询
	查询收入是3000 ,4000 ,5000,8300 所有员工的姓名和收入
	select emp_name,salary from employee where salary in (3000,4000,5000,8300);
	#不在 not in...
	select emp_name,salary from employee where salary not in (3000,4000,5000,8300);

	#模糊查询 like "%" "_" 通配符
	"%" 通配符 以on结尾的员工名搜一下
	select emp_name from employee where emp_name like "%on";
	"_" 通配符 可以限定具体的长度
	select emp_name from employee where emp_name like "a_e_";

	#concat(as 起别名)
	select concat("姓名 : ",emp_name, "  年龄 : ",age) as name_age from employee;
	#concat_ws(拼接的符号,参数1,参数2,参数3)
	select concat_ws(" : " ,emp_name,age) as aa from employee;
	#计算年薪   可以在mysql中使用四则运算符(+ - * /)
	select concat_ws(" : ",emp_name,salary*12) as aa from employee;




#group by子句 分组分类
	
	#group by 字段 对数据进行分类 , by后面接什么字段 , select就搜什么字段
	select sex from employee group by sex;
	select post from employee group by post;
	
	#group_concat 按照分类的形式进行字段的拼接
	搜索年龄大于三十的各部门员工
	select group_concat(emp_name),post from employee where age > 30 group by post;

	#聚合函数
		#count 统计总数 *代表所有
		select count(*) from employee;
		#max   统计最大值
		select max(salary) from employee;
		#min   统计最小值
		select min(age) from employee;
		#avg   统计平均值
		select avg(age) from employee;
		#sum   统计总和
		select sum(salary) from employee;

	#一般情况下 分组+聚合函数 配合使用
	查询部门名以及各部门的平均薪资
	select post,avg(salary) from employee group by post;

	查询部门名以及各部门的最高薪资
	select post,max(salary) from employee group by post;

	查询部门名以及各部门的最低薪资
	select post,min(salary) from employee group by post;

	查询公司内男员工和女员工的个数
	select sex,count(*) from employee group by sex;

	查询部门名以及部门包含的所有员工名字
	select emp_name,post from employee group by post,emp_name;




#having 
	数据在分类分组之后,进行二次数据过滤,
	一般是配合group by 使用,分组之后再过滤
	#找出各部门的平均薪资,并且大于10000以上的部门
	select post,avg(salary) from employee group by post having avg(salary) > 10000;

	#查询各岗位内包含的员工个数小于2的岗位名,查询岗位内包含员工名字和个数
	select post,group_concat(emp_name),count(*) from employee group by post having count(*) < 2;

	#查询各岗位平均薪资小于10000的岗位名,平均工资
	select post,avg(salary) from employee group by post having avg(salary) <10000;

	#查询各岗位平均薪资大于10000且小于20000的岗位名,平均工资
	select post,avg(salary) from employee group by post having avg(salary) between 10000 and 20000;



#order by 排序  按照什么字段进行排序
	asc  升序 : 从小到大 (默认)
	desc 降序 : 从大到小
	
	select *from employee order by age asc; #asc可以不写  默认升序	
	select *from employee order by age desc;

	#查询所有员工信息,先按照age升序,如果age相同则按照hire_date降序
	select emp_name,age,hire_date from employee order by age asc ,hire_date desc;

	#查询各岗位平均薪资大于10000的岗位名,平均工资,结果按平均薪资升序排列
	select post,avg(salary) from employee group by post having avg(salary)>10000  order by avg(salary) asc;

	#查询各岗位平均薪资大于10000的岗位名,平均工资,结果按平均薪资降序排列
	select post,avg(salary) from employee group by post having avg(salary)>10000  order by avg(salary) desc;



#limit 限制查询条数(数据分页)
	limit m,n   m代表从第几条数据查询,n代表查询几条 , m=0代表第一条
	
	select *from employee limit 0,5; #从第一条开始搜,搜5条
	select *from employee limit 5,4; #从第五条开始搜,搜4条

	只查询一条数据
	select *from employee limit 1;
	
	找数据库中最后一条
	select *from employee order by id desc limit 1;
	
	找数据库中最后三条
	select *from employee order by id desc limit 3;


#(了解)可以使用正则表达式查询数据 (不推荐使用,效率不高)
	select * from employee where emp_name regexp ".*on$" # .*? 问号?不识别
	select * from employee where emp_name regexp "^程";
	select * from employee where emp_name regexp "^程.*金";

多表查询

#建表
create table department(
id int,
name varchar(20) 
);

create table employee(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);

#插入数据
insert into department values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');

insert into employee(name,sex,age,dep_id) values
('egon','male',18,200),
('alex','female',48,201),
('wupeiqi','male',38,201),
('yuanhao','female',28,202),
('liwenzhou','male',18,200),
('jingliyang','female',18,204)
;

# 查询:
# 一.找出平均年龄大于25岁以上的部门
# 二.查看技术部门员工姓名
# 三.查看哪个部门没员工
# 四.查询大于平均年龄的员工名与年龄
# 五.把大于其本部门平均年龄的员工名和姓名查出来
# 六.查询每个部门最新入职的那位员工  # 利用上一套数据表进行查询;
# 七.带EXISTS关键字的子查询

#内连接 : (内联查询 inner join) 
	两表或者多表满足条件的所有数据查询出来(两表之间共有的数据)

	两表查询
		select 字段 from 表1 inner join 表2 on 必要关联条件

	多表查询
		select 字段 from 表1 inner join 表2 on 必要关联条件1 inner join 表3 on 必要关联条件2


	#基本语法 inner join on ..  在on后面接上必要的关联条件
	#可以起别名
	#as可以省略
	select *from employee as e inner join department as d on e.dep_id = d.id;


	#where默认实现的就是内敛查询的效果
	select *from employee as e ,department as d where e.dep_id = d.id;

	+----+-----------+--------+------+--------+------+--------------+
	| id | name      | sex    | age  | dep_id | id   | name         |
	+----+-----------+--------+------+--------+------+--------------+
	|  1 | egon      | male   |   18 |    200 |  200 | 技术         |
	|  2 | alex      | female |   48 |    201 |  201 | 人力资源     |
	|  3 | wupeiqi   | male   |   38 |    201 |  201 | 人力资源     |
	|  4 | yuanhao   | female |   28 |    202 |  202 | 销售         |
	|  5 | liwenzhou | male   |   18 |    200 |  200 | 技术         |
	+----+-----------+--------+------+--------+------+--------------+


#外连接
	
	#左连接(左联查询 left join) 以左表为主右表为辅
		#完整查询左表所有数据,右表没有的数据补上null
		select *from employee as e left join department as d on e.dep_id = d.id;
		+----+------------+--------+------+--------+------+--------------+
		| id | name       | sex    | age  | dep_id | id   | name         |
		+----+------------+--------+------+--------+------+--------------+
		|  1 | egon       | male   |   18 |    200 |  200 | 技术         |
		|  5 | liwenzhou  | male   |   18 |    200 |  200 | 技术         |
		|  2 | alex       | female |   48 |    201 |  201 | 人力资源     |
		|  3 | wupeiqi    | male   |   38 |    201 |  201 | 人力资源     |
		|  4 | yuanhao    | female |   28 |    202 |  202 | 销售         |
		|  6 | jingliyang | female |   18 |    204 | NULL | NULL         |
		+----+------------+--------+------+--------+------+--------------+


	#右连接(右联查询 right join) 以右表为主左表为辅
		#完整查询右表所有数据,左表没有的数据补null
		select *from employee as e right join department as d on e.dep_id = d.id ;
		+------+-----------+--------+------+--------+------+--------------+
		| id   | name      | sex    | age  | dep_id | id   | name         |
		+------+-----------+--------+------+--------+------+--------------+
		|    1 | egon      | male   |   18 |    200 |  200 | 技术         |
		|    2 | alex      | female |   48 |    201 |  201 | 人力资源     |
		|    3 | wupeiqi   | male   |   38 |    201 |  201 | 人力资源     |
		|    4 | yuanhao   | female |   28 |    202 |  202 | 销售         |
		|    5 | liwenzhou | male   |   18 |    200 |  200 | 技术         |
		| NULL | NULL      | NULL   | NULL |   NULL |  203 | 运营         |
		+------+-----------+--------+------+--------+------+--------------+


	#全连接(全连接 union) 所有的数据都合并起来
		select *from employee as e left join department as d on e.dep_id = d.id
		union
		select *from employee as e right join department as d on e.dep_id = d.id ;
		+------+------------+--------+------+--------+------+--------------+
		| id   | name       | sex    | age  | dep_id | id   | name         |
		+------+------------+--------+------+--------+------+--------------+
		|    1 | egon       | male   |   18 |    200 |  200 | 技术         |
		|    5 | liwenzhou  | male   |   18 |    200 |  200 | 技术         |
		|    2 | alex       | female |   48 |    201 |  201 | 人力资源     |
		|    3 | wupeiqi    | male   |   38 |    201 |  201 | 人力资源     |
		|    4 | yuanhao    | female |   28 |    202 |  202 | 销售         |
		|    6 | jingliyang | female |   18 |    204 | NULL | NULL         |
		| NULL | NULL       | NULL   | NULL |   NULL |  203 | 运营         |
		+------+------------+--------+------+--------+------+--------------+

子查询

子查询 :嵌套结构
		sql语句中嵌套了另外一条sql语句,用括号()包起来,表达一个整体
		一般应用在from子句后面表达一张表,where子句后面表达一个条件
		查询速度从快到慢 : 单表查询 > 联表查询 > 子查询
+------+--------------+
| id   | name         |
+------+--------------+
|  200 | 技术         |
|  201 | 人力资源     |
|  202 | 销售         |
|  203 | 运营         |
+------+--------------+
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  2 | alex       | female |   48 |    201 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
+----+------------+--------+------+--------+

#找出平均年龄大于25岁以上的部门
	#普通where写法
	select 
		d.id,d.name 
	from 
		employee as e,department as d 
	where 
		e.dep_id=d.id 
	group 
		by d.id,d.name 
	having 
		avg(e.age)>25;

	#inner join
	select 
		d.id,d.name
	from 
		employee as e inner join department as d on e.dep_id = d.id
	group by 
		d.id,d.name
	having 
		avg(e.age) > 25;

	#子查询
		先选出平均年龄大于25岁的部门id
		select dep_id from employee group by dep_id having avg(age) >25;
		通过部门id找部门的名字
		select name from department where id in (201,202)
		综合
		select name from department where id in ( select dep_id from employee group by dep_id having avg(age) >25);


#查看技术部员工姓名
	
	#普通where查询
	select 
		e.name,d.name
	from 
		employee as e,department as d
	where 
		e.dep_id = d.id
		and
		d.name = "技术";


	#inner join 
	select 
		e.name,d.name
	from 
		employee as e inner join department as d on e.dep_id = d.id
	where 
		d.name = "技术";

	#子查询
	找技术部门对应id
	select id from department where name = "技术";
	通过id找员工名字
	select name from employee where dep_id = 200;
	综合
	select name,dep_id from employee where dep_id = (select id from department where name = "技术" );



#查看哪个部门没有员工
	#联表写法(把null的数据露出来,null代表没有)
	select 
		d.id,d.name 
	from 
		department as d left join employee as e on d.id=e.dep_id 
	where 
		e.dep_id is null;

	#子查询
	先查询员工在哪些部门
	select dep_id from employee group by dep_id;
	把不在部门的数据找出来
	select id,name from department where id not in (200,201,202,204 );
	综合拼接
	select id, name from department where id not in (select dep_id from employee group by dep_id );


#查询大于平均年龄的员工名与年龄
	平均年龄 是28
	select avg(age)from employee;
	找出大于平均年龄的人
	select name,age from employee where age > 28;
	综合
	select name,age from employee where age > (select avg(age)from employee );


#把大于其本部门平均年龄的员工名和姓名查出来
	#先计算出各部门的平均年龄是多少
	select dep_id, avg(age)from employee group by dep_id;
	#把查询的各部门平均年龄和过去的employee联表,变成更大的表,方便做单条查询
	select *from employee as e inner join (select dep_id, avg(age) as avg_age from employee group by dep_id) as e1 on e.dep_id = e1.dep_id;
	#筛选
	select 
		*
	from 
		employee as e inner join (select dep_id, avg(age) as avg_age from employee group by dep_id) as e1 on e.dep_id = e1.dep_id 
	where 
		e.age > e1.avg_age;
	

#查询每个部门最新入职的那位员工
	找出每个部门最大的入职时间
	select post,max(hire_date) as max_hd  from employee group by post;
	把子查询搜出来的数据和employee合起来,做单表查询
	#拼接
	
	select 
		e.post,e.emp_name,e.hire_date 
	from 
		employee as e inner join (select post,max(hire_date) as max_hd  from employee group by post) as e1 on e.post = e1.post 
	where 
		e.hire_date=e1.max_hd;



#带EXISTS关键字的子查询
	exists关键字,表达存在
		如果内层sql 能够查到数据 , 返回True , 外层sql执行查询语句
		如果内层sql 不能查到数据 , 返回False, 外层sql不执行查询语句

	select *from employee where exists (select *from employee where id = 1 );
	select *from employee where exists (select *from employee where id = 100 );


子查询总结 : 
	
	子查询可以单独作为一个临时数据,临时的表,临时的字段
	一般用在from where select 子句后面
	可以通过查询出来的临时数据和另外的表结合,变成一张更大的表做单表查询查到想要的数据

python 操作mysql

pccharm中安装pymysql插件

import pymysql

#基本语法:
	
	#创建连接 host user password database 这四个参数必须有
	conn = pymysql.connect(host="127.0.0.1",user="root",password="",database="zzz",charset="utf8",port=3306)
	#创建游标对象 , 该对象可以进行增删改查操作
	cursor = conn.cursor()
	#执行sql语句
	sql = "select *from z1"
	#返回的是数据的总条数
	res = cursor.execute(sql)
	print(res)	# 1
	#获取数据
	res = cursor.fetchone()
	print(res)	#(1, 'zker')
	#释放游标对象
	cursor.close()
	#关闭连接
	conn.close()



#创建/删除 表
	
	conn = pymysql.connect(host="127.0.0.1",user="root",password="",database="zzz")
	cursor = conn.cursor()

	#创建一张表
	sql = """
	create table z2(
	id int unsigned primary key auto_increment,
	first_name char(10) not null,
	last_name char(10) not null,
	age int unsigned,
	sex tinyint,
	money float
	)
	"""
	res = cursor.execute(sql)
	print(res)

	#查看表结构
	sql = "desc z1"
	res = cursor.execute(sql)
	print(res)	#返回字段的个数	6
	res = cursor.fetchone()
	print(res)	#返回真实表内容('id', 'int(10) unsigned', 'NO', 'PRI', None, 'auto_increment')

	#删除表
	sql = "drop table z2"
	res = cursor.execute(sql)
	print(res)






#事务处理
	python 操作事务处理 
	必须通过commit提交数据,才会真正的更新数据
	否则rollback回滚,恢复到以前状态
	

	conn = pymysql.connect(host="127.0.0.1",user="root",password="",database="zzz")
	cursor = conn.cursor()

	sql1 = "begin"
	sql2 = "select *from z1"
	sql3 = "update z1 set name = 'zzzker' where id = 1 "
	sql4 = "commit"
	
	res1 = cursor.execute(sql1)
	res2 = cursor.execute(sql2)
	res3 = cursor.execute(sql3)
	res4 = cursor.execute(sql4)
	
	print(res1,res2,res3,res4)
	print(cursor.fetchone())
	
	cursor.close()
	conn.close()

sql注入攻击

#创建一张表
create table user_pwd(
id int unsigned primary key auto_increment,
username varchar(255) not null,
password varchar(255) not null
)


#sql注入问题
import pymysql

user = input("user>>> : ").strip()
pwd = input("password>>> : ").strip()

conn = pymysql.connect(host="127.0.0.1", user="root", password="", database="zzz")
cursor = conn.cursor()

sql = "select * from user_pwd where username = '%s' and password = '%s' " % (user, pwd)
print(sql)

res = cursor.execute(sql)
print(res)

if res:
	print("welcome")
else:
	print("get out fuck you! ")

cursor.close()
conn.close()

输入 : qwer' or 1=1 -- asdasd  和 asd  也可以登陆成功
select * from user_pwd where username = 'qwer' or 1=1 -- asdasd' and password = 'asd'
where username = 'qwer' or 1=1 后面的判断是假的 但是or拼接条件为真,所以可以查询成功
-- 代表后面的代码被注释掉了
把用户名和密码全都绕开 , 进行sql注入攻击




#解决办法

使用预处理机制, 可以避免大多数的sql注入问题
execute 参数1是一个sql语句, 如果sql语句和里面的参数值分开执行,默认开启预处理
execute(sql , (参数1,参数2,参数3))

import pymysql
user = input("user>>> : ").strip()
pwd = input("password>>> : ").strip()

conn = pymysql.connect(host="127.0.0.1",user="root",password="",database="zzz")
cursor = conn.cursor()

sql = "select * from user_pwd where username = %s and password = %s"
res = cursor.execute(sql , (user,pwd))

print("welcome" if res else "get out fuck you !!!")

cursor.close()
conn.close()

python 操作mysql 增删改查

import pymysql

python 操作mysql的时候,默认开启事务,必须在增删改之后
提交数据, 才会对数据库产生影响, 否则默认回滚

提交数据 : conn.commit()
回滚数据 : conn.rollback()

execute 执行单条sql语句
executemany  执行多条sql语句


#创建连接 
	conn = pymysql.connect(host="127.0.0.1",user="root",password="",database="zzz")

#查询数据,默认是元组 , 可以设置返回字典类型
	在括号中指定 pymysql.cursors.DictCursor
	cursor = conn.cursor(cursor = pymysql.cursors.DictCursor)

#增
	sql = "insert into z2(first_name,last_name,age,sex,money) values(%s,%s,%s,%s,%s)"
	
	#一次插入一条数据
		res = cursor.execute(sql,("李","大炮",18,1,9999))
		print(res)


	#一次插入多条数据
		res = cursor.executemany(sql,[("李","大炮",18,1,9999),("谢","晨",80,0,200),("尉","翼麟",18,1,12000)])
		print(res)


	#获取最后插入这条数据的id号
	#(针对单挑数据执行,获取最后的id,如果多条数据执行,以第一条数据id为主)
		print(cursor.lastrowid)
	
	
	#针对多条数据最后的id,可以通过倒序查询,找到id号
		select *from z2 order by desc limit 1


#删
	sql = "delete from z2 where age = %s"
	res = cursor.execute(sql,(18,))
	print(res)
	
	if res :
		print("删除成功")
	else:
		print("删除失败")



#改
	sql = "update z2 set first_name = %s where age = %s"
	res = cursor.execute(sql,("李",80))
	print(res)

	if res:
		print("111")
	else:
		print("222")


#查


	sql = "select * from z2"
	res = cursor.execute(sql)
	print(res)	#返回总条数



	#获取一条数据 fetchone
		res = cursor.fetchone()
		print(res)	#{'id': 36, 'first_name': '李', 'last_name': '晨', 'age': 80, 'sex': 0, 'money': 200.0}



	#获取多条数据 fetchmany
		默认从上一条数据继续往下搜索(类似迭代器)
		data = cursor.fetchmany()	#没有参数默认只取一条
		data = cursor.fetchmany(3)
		print(data)
		
		'''
		[
		{'id': 58, 'first_name': '李', 'last_name': '大炮', 'age': 18, 'sex': 1, 'money': 9999.0},
		{'id': 59, 'first_name': '谢', 'last_name': '晨', 'age': 80, 'sex': 0, 'money': 200.0}, 
		{'id': 60, 'first_name': '尉', 'last_name': '翼麟', 'age': 18, 'sex': 1, 'money': 12000.0}
		]
		
		'''
	
	#遍历拿出数据
		for row in data:
			first_name = row['first_name']
			last_name = row['last_name']
			age = row['age']
			if row['sex'] == 0:
				sex = "女性"
			else:
				sex ="男性"
			print("姓: {}\n名字 : {}\n年龄 : {}\n性别 : {}".format(first_name,last_name,age,sex))



	#获取所有数据 fetchall 
		基于上一条数据往下搜索(类似于迭代器)
		data = cursor.fetchall()
		print(data)
		


	#自定义搜索查询的位置
		sql = "select *from z2 where id >= 60"
		res = cursor.execute(sql)
		print(res)
		
		res = cursor.fetchall()
		print(res)



	#相对滚动(向后)
		cursor.scroll(3,mode="relative")
		res = cursor.fetchone()
		print(res)

	#相对滚动(向前)
		cursor.scroll(-3,mode="relative")
		res = cursor.fetone()
		print(res)

	无论向前还是向后都不能超出范围
	


	#绝对滚动 , 永远基于第一条数据位置滚动
		cursor.scroll(0,mode="absolute")
		print(cursor.fetchone())
		
		cursor.scroll(1,mode="absolute")
		print(cursor.fetchone())
		
		cursor.scroll(2,mode="absolute")
		print(cursor.fetchone())

		#向前滚动没有数据,超出范围error
			
			#IndexError: out of range
			cursor.scroll(-1,mode="absolute")
			print(cursor.fetchone())
		

在进行增删改的时候 
必须通过commit提交数据
才会更新数据库
否则默认回滚

conn.commit()
cursor.close()
conn.close()

导出/导入数据库

#导出
	
	第一步 : 先退出数据库
	
	第二步 : 切换到对应的导出路径
	
	第三步 : 
		#导出所有
		mysqldump -uroot -p 数据库名 > 数据库名.sql
		
		#导出单个
		mysqldump -uroot -p 指定数据库名 表名 > 表名.sql


#导入
	
	第一步 : 先创建一个空的数据库
	
	第二步 : 找到对应的sql文件的路径
	
	第三步 : source 路径/sql文件

innodb 在只有frm和ibd文件的情况下,如何恢复数据;

安装 MySQL Utilities
https://downloads.mysql.com/archives/utilities/ 

cmd中找到frm那个文件,执行如下命令:
切换到对应目录,执行下面语句,不要加分号
mysqlfrm --diagnostic ./文件目录/t1.frm
查出建表语句,复制查询出来的建表语句在mysql中创建的新数据中使用


#对已创建的表进行表空间卸载 删除ibd文件
mysql> alter table t1 discard tablespace;


把要恢复的idb文件替换进去


#对已创建的表进行空间装载
mysql> alter table employee import tablespace;

sql语句优化

#mysql执行流程

	客户端:
		发送连接请求 , 连接建立成功后发送增删改查sql语句执行

	服务端:
		1.连接层:提供和客户端连接的服务 , 在tcp协议下
				 提供多线程并发的技术,让多个用户登陆到mysql中
		
		2.服务器:提供了各种接口(增删改查)
				 分析器组件会解析用户的sql语句
				 如果发现了sql语句执行效率较低,会提交给优化器组件进行优化再执行
				 (查询缓存:把上次搜过的数据或者提前存储的数据直接返回,效率快)
				 (优化器:mysql query optimizer)
		
		3.存储引擎:
				 存储或者提取数据
				 innodb: 支持事务处理,支持行锁,支持高并发
				 myisam: 支持表锁,不支持高并发
		
		4.日志文件:
				 产生binlog日志(二进制文件)


#可以通过设置来决定自增起始位置
	create table ceshi_table1(
	id int primary key auto_increment,
	name varchar(255)
	)engine = myisam auto_increment=3 charset=utf8;


#sql卡顿原因
	硬盘读写数据,io延迟高,sql语句性能低,导致sql执行的时间漫长
	表中的数据没有任何索引,并且数据量较大,也会造成sql语句执行速度慢

	sql语句在编写时:
		select ... from .. join on where .. group by . having .. order by .. limit..

	sql语句在执行时:
		from .. join on .. where . group by having select order by limit


#索引
	
	#索引(index)概念
		是一个树状的数据结构,即(B树结构,分支节点>2)
		相当于字典的目录,功效是加快查询速度
		常用树:B树(banlance-tree),二叉树,红黑树,hash树
	
	#树节点概念
		根节点(最顶级节点)
		分支节点(父节点,子节点)
		叶子节点(最后一层存储数据的节点)
		树的高度(树的层级,理想情况下是三级,任何数据最多需要3次查到,支持百万级别的数据查询,追求树的矮胖结构)
		
	[b+]: 在相邻的叶子节点上,加入双向链表(指针),当前叶子节点不但保存数据,还保存上下两个节点的地址(小范围数据中加快查询数据)
	[b*]: 在相连的分支节点上,加入双向链表(指针),当前叶子节点不但保存数据,还保存上下两个节点的地址(大范围数据中加快查询数据)
	
	(磁盘块 block 数据页 最大16kb)
	myisam和innodb都是b+树结构



#innodb和myisam 的索引结构
	
	1.聚集索引[innodb存储引擎的特点,myisam不支持]
		
		如果有主键,自动以主键创建聚集索引的数据结构(树状结构)
		如果没有主键,选择唯一键
		都没有的话会自动生成隐藏的聚集索引,分出一个字段占用6个字节长整型
		
		叶子节点上面直接存储真实数据(索引和数据捆绑在一起)
		分支节点存储的是索引的最小值,用来划分范围
		在数据量变大的时候,尽量在树层级高度不变的情况下,横向发展
		好处:查询次数少,提升效率,减少io阻塞
	
	2.非聚集索引(辅助索引,二级索引,普通索引)
		
		先对创建索引的该字段划分区间进行排序,把索引值分布在叶子节点上
		存储的是该字段的值以及对应映射出的主键id(primary key),没有存真实数据
		通过主键id,再去从其他文件中找数据
		
	3.两者区别
		
		myisam和innodb使用的索引结构都是b+树,但是叶子节点存储的数据不同
		innodb文件结构中只有frm和idb  直接把数据存在叶子节点上
		myisam文件结构中有frm,myi,myd 叶子节点上存储的索引值,通过索引找id,通过id找数据
		
	4.性能优化
		
		利用索引查询时,可以增快查询速度,但是增删改速度变慢,会改变树状结构
		追求尽量让叶子节点存储的数据类型小一点,让高度变矮,让数据页变少

索引

#常用索引
	单个字段索引
		主键索引 primary key : 非空且唯一
		唯一索引 unique      : 唯一
		普通索引 index       : 单纯加索引,为了提升查询效率
	联合索引
		primary key(字段1,字段2) :联合主键索引
		unique(字段1,字段2)      :联合唯一索引
		index(字段1,字段2)       :联合普通索引

#应用场景
	编号:int
	姓名:varchar(255)
	身份证号:char(18)
	电话:char(11)
	地址:varchar(255)
	备注:text
	姓:varchar(255)
	名:varchar(255)
	
	编号:主键
	姓名:普通索引(注意在区分度高的字段上加)
	身份证:unique
	电话:unique
	备注:全文索引, 借助第三方软件sphinx来运行
	姓和名:联合索引,联合在一起查,加快速度


#不同的存储引擎支持的数据结构
	
	innodb : 支持b-tree  fulltext 不支持hash类型索引结构
	myisam : 支持b-tree  fulltext 不支持hash类型索引结构
	memory : 支持b-tree  hash类型 不支持fulltext索引结构
	
	hash类型索引 : 数据放内存中,通过键来获取值,单条数据查询快,范围内查询慢
	b-tree       : 最理想的三层结构,理论上可以支撑百万条数据的查询


#建立索引
	
		+-------+----------+------+-----+---------+-------+
		| Field | Type     | Null | Key | Default | Extra |
		+-------+----------+------+-----+---------+-------+
		| id    | int(11)  | NO   | PRI | NULL    |       |
		| name  | char(10) | YES  | MUL | NULL    |       |
		+-------+----------+------+-----+---------+-------+
	
	
	#方法1 建表时直接创建索引,index索引名(索引字段)
		create table t1(
		id int primary key,
		name char(10),
		index index_name(name)
		);


	#方法2 建表之后,创建索引 create index 索引名 on 表名(索引字段)
		create table t2(
		id int primary key,
		name char(10)
		);
		create index index_name on t2(name)


	#方法3 改字段变索引 alter table 表名 add index 索引名(索引字段)
		create table t3(
		id int primary key,
		name char(10)
		);
		alter table t3 add index index_name(name);

	#删除索引
		drop index index_name on t3;
		+-------+----------+------+-----+---------+-------+
		| Field | Type     | Null | Key | Default | Extra |
		+-------+----------+------+-----+---------+-------+
		| id    | int(11)  | NO   | PRI | NULL    |       |
		| name  | char(10) | YES  |     | NULL    |       |
		+-------+----------+------+-----+---------+-------+



#正确使用索引
	
	alter table s1 add index index_id(id);
	select *from s1 where id = 5;
	
	#使用索引和不使用索引差别很大,但是加了索引之后会让ibd文件变大


	#把频繁作为搜索条件的字段作为索引,查单挑数据
	 如果查询的是一个大范围数据,则不能命中索引
	 表达范围的符号 : < > <= >= != like between and  .. in 
	 select * from s1 where id>5;	#无法命中索引
	 select * from s1 where id<5;	#小范围可以命中


	#选一个区分度较高的字段作索引
		选区分度低的字段做了索引,在查询数据的时候,先走索引建好的树状结构,再把数据搜出来
		因为树状结构中有大量的重复数据,会增加树的高度,反而速度不快,冗余数据过多
		
		默认系统会把主键或者unique标识的约束,自动创建索引,因为区分度较高,没有冗余数据

		create index index_name on s1(name);#不推荐使用区分度低的字段作为索引
	
	#在搜索条件中,不能让索引字段参与计算,不能命中索引
		select *from s1 where id = 3000;
		select *from s1 where id*3 = 3000;#不推荐
		


	#当条件中含有and , sql语句会通过优化器进行优化
		
		如果有and相连,找到第一个有索引的并且树的高度最矮字段进行优化
		select count(*) from s1 where email="xboyww1000@oldboy";
		select count(*) from s1 where email="xboyww1000@oldboy" and id = 1000; 		#ok
		select count(*) from s1 where email="xboyww1000@oldboy" and name = "xboyww";
		select count(*) from s1 where email = "xboyww1000@oldboy" and name =  "xboyww" and id = 1000;	#ok


		如果有or相连,没有优化,所有语句从左到右执行,让索引失去意义
		select count(*) from s1 where id = 1000 or email="xboyww1000@oldboy";


	#联合索引 : 遵循最左前缀原则 index(字段1,字段2,...)
		drop index index_id on s1;
		drop index index_name on s1;
		create index union_index on s1(first_name,last_name);

		select count(*) from s1 where first_name = "王6" and last_name="文6";	#ok
		select count(*) from s1 where last_name="文6" and  first_name = "王6";	#ok
		select count(*) from s1 where last_name="文6"; # 不能命中索引
		select count(*) from s1 where first_name="王6" and gender="man";
		select count(*) from s1 where first_name="王6" and gender="man" and name="xboyww";
		#最左前缀原则:被标记成MUL这个字段,必须存在在搜索条件中,就会命中索引
		first_name + ...(必须该字段存在) 联合索引会更加精确的命中想要的数据,数据结构更合理


	#其他
		# 数据类型不匹配,不能命中索引
		select count(*) from s1 where first_name = 100
		# 使用了函数不能命中
		select count(*) from s1 where reverse(first_name) = "6王";

part1 索引树高度

 1.表的数据量
	数据量越大,树的高度就会变高,理论上三层索引树的高度最为理想,可以支持百万级别的数据量
	解决: 可以使用分表(横切,竖切),分库,增加缓存,解决数据量大,查询慢
	
 2.索引键值过长
	该索引字段存储数据太大,每个叶子节点最大存储16k,超过这个范围会新增加叶子节点和分支节点
	解决:前缀索引(截取前5个长度)

3.数据类型
	char(定长) varchar(变长) 从开辟空间速度来看,char快
	从数据结构上来看,varchar更为合理
	
	
	(1) 避免使用select *,不确定表大小的时候,使用count(*) 查一下数据
	(2) 尽量使用数据类型较小的字段做索引
	(3) 重复值少的,区分度高的字段索引,性别这样的字段不要做索引
	(4) 在多表查询时使用join,尽量少的使用子查询

part2 执行计划分析

"""desc/explain"""
 执行计划: 在一条sql执行之前,制定执行的方案
desc select * from s1;

 1.select_type
simple   代表的是简单查询(单表查询,不包括子查询,union)
primary  sql嵌套中的主查询(最外层)
subquery sql嵌套中的子查询(最里面)
derived  衍生查询(把子查询结果作为一张临时表)

 2.table
在多表或者子查询时候,通过table分析出问题的表是谁.

 3.type
	# 显示执行计划的类型,优先级从低到高如下, 优化时,至少达到range 或者 ref 级别
all < index < range < ref < eq_ref < const < system
		
		# 1.all 全表扫描 (不走索引) 慢查询
		(1)在大范围内查询 > < >= <= != between and  in like ...
		(2)where条件中有计算,有函数
		(3)数据类型不匹配
		(4)拼接条件使用or
	
		# 2.index 全索引扫描
		"""扫描整个索引树,才能获取到所有数据,这样的索引失去意义"""
		desc select count(*) from s1;
	
		# 3.range 索引范围扫描(注意点:范围太太,不能命中索引)
		desc select * from s1 where id < 10;      # type = range
		desc select * from s1 where id < 1000000; # type = all
		desc select * from s1 where id between 1 and 10;  # type => range
		desc select * from s1 where id between 1 and 1000000; # type => all
		desc select * from s1 where email like "%w%"; # type => all
		desc select * from s1 where email like "w%";  # type => range  (去掉左边的%)
		"""如果范围过大,不能命中索引,如果范围适当,可以命中索引"""
	
		# 对in或者or这样的语句进行优化 
		desc select * from s1 where id in (1,2);
		"""优化:union all 比 union 速度快, union在合并数据之后,多一步去重操作"""
		desc select * from s1 where id = 1
		union all
		select * from s1 where id = 1;
	
		desc select * from s1 where id = 1
		union
		select * from s1 where id = 1;
		
		# 优化or条件
		desc select * from s1 where id = 10 or name = "aaaaa"
	
		desc select * from s1 where id = 10
		union all 
		select * from s1 where name = 'aaaaa';
	
		# 4.ref 普通索引查询(非唯一)
		desc select * from s1 where email = "xboyww10@oldboy";
		desc select * from s1 where id = 10; # 此时id设置是普通索引
	
		# 5.eq_ref 唯一性索引(联表)
		"""要求: 应用在多表联查中,被关联的字段需要主键或者唯一,表之间的关系为一对一并且数据条数相同"""
		desc select student1.age from student1,class1 where student1.class_id = class1.id
		alter table class1 add primary key(id);
		delete from student1 where id = 3;
	
		# 6.const:主键或者唯一索引(单表)
		""" 针对于primary key  和 unique 索引等值查询 """
		desc select * from class1 where id = 1 # type => const
		desc select * from class1 where id > 1 # type => range
	
		# 7.system(了解)
		"""只有一条数据的系统表"""

 4.possible_keys : 执行sql时,可能用到的索引是谁
 5.key           : 执行sql时,实际用到的索引是谁
	show index from s1; # 展现所有的索引

 6.key_len : 判断联合索引覆盖的长度(通过字节数可以判定出到底触发了哪些联合索引字段)
	在没有not null 约束的时候,默认预留一个字节,标记是空或者非空
	utf8 通常情况下,中文1个字符占用3个字节,字母占用1个字节,极个别的生僻字占4个字节
	varchar 每次存储数据的时候,系统底层默认会额外预留2个字节
			  有not null(不为空)    没有not null(可为空)
	tinyint    1                     1+1
	int        4					 4+1
	char(5)    5*3				   	 5*3+1
	varchar(5) 5*3 + 2				 5*3+2+1


# 把数据表中的数据导入
+------+----+------+----+------+----+
| n1   | n2 | n3   | n4 | n5   | n6 |
+------+----+------+----+------+----+
|    1 |  2 | a    | b  | aa   | bb |
|    1 |  2 | a    | b  | aa   | bb |
|    1 |  2 | a    | b  | aa   | bb |
|    2 |  2 | a    | b  | cc   | dd |
+------+----+------+----+------+----+
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| n1    | int(11)    | YES  | MUL | NULL    |       |
| n2    | int(11)    | NO   |     | NULL    |       |
| n3    | char(5)    | YES  |     | NULL    |       |
| n4    | char(5)    | NO   | MUL | NULL    |       |
| n5    | varchar(5) | YES  |     | NULL    |       |
| n6    | varchar(5) | NO   |     | NULL    |       |
+-------+------------+------+-----+---------+-------+
n1 -> 5B  n2 -> 4B n3 ->16B   5+4+16 = 25
desc select * from t100 where n1 = 2 and n2 = 2 and n3 ="a"; # 命中n1 n2 n3
desc select * from t100 where n1 = 1 and n2 = 2 and n3 ="a"; # 如果有重复数据,不会触发联合索引
desc select * from t100 where n1 = 1 and n2 = 2 ;# 如果有重复数据,不会触发联合索引
desc select * from t100 where n1 = 2 and n2 = 2 ;# n1 -> 5B  n2 -> 4B 命中n1 , n2
desc select * from t100 where n1 = 2;# n1 -> 5B 命中n1
desc select * from t100 where n1 = 2 and n3 = "a"; # n1 -> 5B 命中n1 没有命中n3
desc select * from t100 where n2 = 2 and n3 = "a"; # 符合最左前缀原则,在没有n1的情况下不能触发;

# 联合索引: index(a,b,c) -> a , ab , abc 创建了三组索引 ,符合最左前缀原则,第一个字段必须存在才能触发;

part3 事务处理的四项特征 ACID

A.原子性:
	同一个事务中执行多条sql语句,要么全部成功,要么直接回滚,作为一个完整的整体,不能再继续分隔的最小个体
	
C.一致性:
	a,i,d 都是为了保证数据的一致性才提出来的,比如约束,键在插入数据时,必须按照要求插入,保证规则上的一致性,
	上升到事务中,如果出现意外导致数据不统一,例如脏读,幻读,不可重读,最终要保证数据是一致的
	上升到主从数据库,主数据库增删改,从数据也要进行同步改变,保证数据的一致性;
	
I.隔离性:
	lock + isolation锁,来处理事务的隔离级别
	一个事务和另外一个事务工作过程中彼此独立隔离
	
D.持久性:	
	把数据写到磁盘上,保证数据持久化存储不丢失.

 隔离性 :  隔离级别

脏读 : 没提交的数据被读出来了
不可重读 : 前后多次读取,结果数据内容不一样(同一个会话里,在不修改的情况下,永远只看到同样的一份数据)
幻读 : 前后多次读取,结果数据的总量不一样

RU : 读未提交 : 脏读,不可重读,幻读 READ-UNCOMMITTED 
RC : 读已提交 : 防止脏读,会出现不可重读和幻读  READ-COMMITTED
RR : 可重复读 : 防止脏读,不可重读 ,可能会出现幻读 REPEATABLE-READ 
SR : 可串行化 : 防止一切(但是会把异步并发的程序变成同步程序,不能并发,性能差)

 查询当前mysql的隔离级别  (默认是RR)
select @@tx_isolation;
 查询是否自动提交数据
select @@autocommit;

 修改mysql配置文件
D:\MySQL5.7\mysql-5.7.25-winx64\my.ini
 更改隔离级别
transaction_isolation =  READ-UNCOMMITTED 
 不让系统自动提交数据
autocommit = 0



 重启mysql
net stop mysql
net start mysql

 1.脏读
READ-UNCOMMITTED 
先去调整设置,重启mysql ,尝试在一个窗口里通过事务,更改一条数据,开启另外一个窗口尝试读取,会出现问题

 2.不可重复读
 窗口1
begin;
update t1 set k1="abc" where id = 1
select * from t1;
commit;

 窗口2
select * from t1; 数据也跟着改了是不可重读


 3.幻读
 窗口1
begin;
insert into t1 values(4,'c',50);
select * from t1;
commit;

 窗口2
select * from t1; 数量也跟着增加了是幻读


4.通过二次提交commit , 可以让多用户同步数据;
commit;


 5.事务应用的计数(了解)
(1) RR级别下,解决不可重读,使用mvcc技术,生成最新的mysql的系统备份(快照),然后读取快照
(2) RR级别下,解决幻读,gap 间隙锁 next-lock 下一键锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值