一 概念
1 数据库诞生和发展历史
数据库: 按照数据结构来组织,存储,管理数据的仓库
诞生
计算机的发明是为了做科学计算的,而科学计算需要大量的数据输入和输出。
早期是通过打孔机和灯泡来表示数据的输入和输出。
后来,数据可以存储在磁带上,顺序的读,写入磁带
1956年IBM发明了磁盘驱动器,其支持了随机访问,不再是之前的顺序访问。
随着信息时代的到来,有了硬件存储技术的发展,有大量的数据需要存储和管理,数据库管理系统DBMS就诞生了。
不管使用什么存储介质,数据库的数据模型才是其核心和基础。
2 早期数据库分类
按照数据模型分类: 网状数据库,层次数据库,关系型数据库
1 层次数据库
以树形结构表示实体之间的关联,关系只支持一对多,树不能有交叉,代表数据库有IBM 的 IMS
2 网状数据库
通用电气最早在1964年开发出网状数据库IDS,只能运行在GE自家的主机上
节点描述数据,节点的联系就是数据之间的关系
能够直接描述客观世界,可以表示实体键多种复杂关系,而这是层次数据库无法做到的,比如,一个节点可以有多个父节点,节点之间可以支持多对多的关联。
3 关系数据库
使用行,列组成的二维表来组织数据和关系,表中行(记录)即可描述数据实体。也可描述实体键的关系。
关系模型比网状模型,层次模型更简单,不需要关系数据存储的物理细节,专心于数据的逻辑构建,而关系模型有论文的严格的数学理论基础支持。
1970 年,IBM E.F.Codd发表了名为"A Relational Model of Data for large Shared Data Banks"的论文,提出来关系模型的概念,奠定了关系模型的理论基础,关系模型,有严格的数据基础,抽象级别较高,简单清晰,便于理解和使用。
基于关系模型构建的数据库成为RDBMS(Relational DataBase System)。
3 关系型数据库发展历史
1 Oracle 发展
Larry Ellison 在IBM的关系数据库论文的基础上,发展出通用商用的数据库Orcale,1992年,Oracle7 才渐渐稳定下来,并取得巨大成功,2001年的9i版本本广泛应用。
2009年4月20日,甲骨文公司宣布将以每股9.50美元,总计74亿美元收购sun(计算机系统)公司,2010年1月成功收购
2013 年,甲骨文超过IBM,成为继微软之后的第二大软件公司
2 MySQL 发展
1985年几个瑞典人为大型零售商项目设计了一种利用索引顺序存取数据库的软件,这就是MyISAMd的前身,1996年。MySQL1.0 发布,随后发布了3.11.1版本,并开始往其他平台移植,200年MySQL采用GPL协议开源,MySQL4.0开始支持MyISAM,InnoDB存储引擎,2005年10月,MySQL 5.0 称为里程碑版本。
2008年1月被sun公司收购
2009年1月,在Oracle收购MySQL之前,Monty Wideniusa担心收购,就从MySQL Server 5.5 开始一条存的GPL分支,起名为MariaDB
MySQL 的引擎是插件化的,可以支持很多引擎
MyISAM,不支持事务,插入,查询速度快
InnoDB,支持事物,行级锁,MySQL 5.5 起的默认引擎
3 NoSQL
NoSQL 是对非SQL,非传统关系型数据库的统称
NoSQL一词诞生于1998年,2009年这个词汇被再次提出指非关系型,分布式,不提供ACID的数据库设计模式随着互联网时代的到来,数据爆发式增长,数据库技术发展日新月异,要适应新的业务需求,随着移动互联网,物联网的到来,大数据的技术中NoSQL也同样重要。
二 MySQL数据库概述和SQL基本操作
1 MySQL数据库概述
MySQL数据库是一种关系型数据库管理软件,支持网络访问,默认端口是3306
MySQL通信使用的是mysql协议
MySQL的底层是基于TCP协议的。因为UDP会丢包,而数据库的数据是绝对不能丢包的。
2 SQL
1 概述
SQL 是结构化查询语言Structured Query Language,1987年被ISO组织标准化,所有主流的关系型数据库都支持SQL,NoSQL也有很大一部分支持SQL。
SQL 语句分为:
DDL : 数据定义语言,负责数据库定义,数据库对象定义。由CREATE,ALTER 和 DROP 三个语法组成
DML: 数据操作语言,负责对数据库对象的操作,CRUD增删改查
DCL: 数据库控制语言,负责对数据库权限访问控制,由GRANT 和 REVOKE 两个指令组成
TCL : 事务控制语言,负责处理ACID事务,支持commit,rollback 指令
SQL 语句对大写不敏感,SQL语句的末尾应该使用分号结束。
2 数据库基本术语
1 PRIMARY KEY 主键
表中一列或多列组成唯一的key,.也就是通过这一个或多个列能唯一标识一条记录,主键的列不能有空,及不能有NULL,主键往往设置为整数类型,长整数类型型,且自增AUTO_INCREMENT,表中可以没有主键,但是,一般的表设计中,都会包含主键。
主键用过了不回头,就算删除了当前主键的值,下一条插入语句也会从下一个数字进行存储。
2 索引 index
可以看做是一本大字典的目录,为了快速检索使用,空间换时间,显著提升查询效率,可以对一列或多列设定索引。
主键索引,主键会自动建立主键索引,主键本身就是为了快速定位唯一记录的。
唯一索引,表中的索引列组成的索引必须唯一,但可以是空,非空值必须唯一,空值可以有多个
普通索引,没有唯一性要求,就是构建了一个字典目录而已
索引也有副作用,能显著提升查询效率,但会导致插入和删除效率低下。
3 约束 Constraint
UNIQUE 约束(唯一键约束)
定义了唯一索引,就定义了唯一键约束
PRIMATY KEY 约束
定义了主键,就定义了主键约束
外键约束 Foreign Key
外键: 在B表中的列,关键A表中的主键,B表中的列就是外键
如果在表B中插入一条数据,B中的外键插入一个值,这个值必须在表A中是存在的主键的值,修改表B的外键的值也是同样的,外键对应的值必须在表A的主键中存在如果表A要删除一条记录。那么就等于删除了一个主键,如果表B中引用了这个主键,就必须先删除表B中引用这个主键的记录,才能删除表A中的记录,否则会导致删除失败
修改表A的主键,由于主键唯一性,修改的主键相当于插入新的主键,那么表B引用这个主键,将组织表A修改主键,必须删除表B的相关记录后,才能修改表A的主键。
外键约束,为了保证数据完整性,一致性,杜绝数据冗余,数据讹误。
4 视图
视图,也成虚表,看起来像表,它是由查询语句生成的,可以通过视图进行CRUD操作,
视图的作用: 简化操作,将复杂查询SQL语句定义为视图,可以简化查询
数据安全,视图可以只显示真实表的部分列,或计算后的结果,隐藏真实表的数据。
3 MySQL中的数据类型
类型 | 含义 |
---|---|
tinyint | 1 字节,带符号的范围是-128到127,无符号的范围是0到255,bool或boolenan,就是tinyint,0 表示假,非0表示真 |
smaillint | 2 字节,带符号的返回为-32768到32767,无符号是0到65535 |
int | 整数类型,4字节,同integer,带符号的范围是-2147483648到2147483647,无符号的范围是0到4294967295 |
bigint | 长整数类型,8 字节,带符号的范围是-9223372036854775808到9223372036854775807,无符号数是0到18446744073709551615 |
float | 单精度浮点数精确到大约7位小数 |
dobule | 双精度浮点数精确到大约15位小数 |
DATE | 日期。支持的范围是1000-01-01到9999-12-31 |
DATETIME | 支持的范围是 1000-01-01 00:00:00 9999-12-31 23:59:59 |
TIMESTAMP | 时间戳。范围是'1970-01-01 00:00:00' 到 2037年 |
char(M) | 固定长度,右边填充空格已达到长度要求,M为长度,返回为0-255,M值的是字符个数 |
varchar(M) | 变长字符串,M表示最大列长度,M的范围是0到65535,但不能突破行最大字节数 65535 |
text | 大文本,最大长度为 65535(2^16-1)个字符 |
BLOB | 大字节,最大长度为 65535(2^16-1)字节的BLOB列 |
LENGTH 函数返回字节数,而char 和varchar 定义的M是字符数限制
char 可以将字符串变成等长,空间换时间,效率略高,varchar变长,节省了空间。
4 MySQL 操作基本语言
1 DCL
GRANT 授权 REVOKE 撤销
GRANT ALL ON *.* TO admin@localhost IDENTIFIED BY 'Admin@Roo123';
参数说明:
其中 ALL,代表授予所有权限,当然可以单独授予 SELECT,DELETE,UPDATE等权限
ON 后面的*.* 表示库和表,如test.*,则表示test库中的所有表,test.test则表示test库中的test表,TO 后面的admin 表示用户名 @ 后面的localhost表示本地授权登录,当然可以使用'%'表示所有都可登录,
IDENTIFIED BY 后面的表示密码.
使用此命令即可登录成功
mysql -uadmin -pAdmin@Roo123
REVOKE 撤销权限
REVOKE ALL ON *.* FROM admin@localhost;
参数说明:
此中的ALL 也是所有的权限,也可以撤销部分权限,如SELECT,DELETE等
ON 后面的和上述相同
FROM 后面的表示的是用户名和允许登录的范围登录查询
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)
其只能管理这个开放库了
2 DDL
1 删除用户
DROP USER admin@localhost;
此时将不能登录
[root@python ~]# mysql -uadmin -pAdmin@Roo123
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'admin'@'localhost' (using password: YES)
2 创建数据库
库是数据的集合,所有数据按照数据模型组织在数据库中
CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CHARACTER SET 是指定字符集,utf8mb4 是utf8 的扩展,支持4字节的utf8mb4,需要大于MySQL 5.5.3+
COLLATE 指定字符集的校对规则,用来做字符串的比较的。删除数据库
DROP DATABASE IF EXISTS test;
创建数据表
表分为行和列,MySQL是行存储数据,数据是一行行存储的,列必须固定多少列。
行Row,也成为记录Record,元祖
列 Column,也成为字段Field
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL COMMENT '主键',
`birth_date` date NOT NULL COMMENT '生日',
`first_name` varchar(14) NOT NULL COMMENT '用户-姓',
`last_name` varchar(16) NOT NULL COMMENT '用户-名',
`gender` enum('M','F') NOT NULL COMMENT '性别',
`hire_date` date NOT NULL COMMENT '入职时间',
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
反引号标注的名称,被认为是非关键字
不同数据类型占用字节数不同
数字范围决定了存储方式,小范围整数使用字符串比较合适,大范围整数则使用数字类型存储比较合适。NOT NULL 不能为空
定义字段完成后定义约束,如上述的PRIMARY KEY (
emp_no
) 则被称为主键约束
3 DESC 查询列信息
mysql> DESC employees;
+------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| emp_no | int(11) | NO | PRI | NULL | |
| birth_date | date | NO | | NULL | |
| first_name | varchar(14) | NO | | NULL | |
| last_name | varchar(16) | NO | | NULL | |
| gender | enum('M','F') | NO | | NULL | |
| hire_date | date | NO | | NULL | |
+------------+---------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
mysql> DESC employees '%name';
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| first_name | varchar(14) | NO | | NULL | |
| last_name | varchar(16) | NO | | NULL | |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
4 Navicat premium 基本设计表原则
设计一个登陆表
1 基本上必须有主键,且必须是无符号的自增序列
2 loginname 必须不能为空,若为空,则会出问题,password也不能为空
3 必须要有冗余字段,因为线上业务若正在运行,则添加字段可能导致线上业务的中断或用户体验相关的问题
4 必须设置索引,以加快select查询速度
查看自动递增数字
查看生成SQL
CREATE TABLE `login` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`loginname` varchar(48) NOT NULL COMMENT '登录名',
`username` varchar(48) DEFAULT NULL COMMENT '用户名',
`password` varchar(255) NOT NULL COMMENT '用户密码',
`revered1` varchar(255) DEFAULT NULL,
`revered2` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ln` (`loginname`) USING BTREE COMMENT '登录名称索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5 SQL 导入
1 选择表,右键选择运行SQL文件
工具创建视图
选择视图和创建工具
将需要创建的视图拉入框内,并选择对应的列来完成视图的创建工作
保存
预览
3 DML
1 关系操作
关系:在关系数据库中,关系就是二维表
关系操作就是对表的操作
选择 (select): 又称为限制,是从关系中选择出满足给定条件的元祖
select * from test where id=1
投影(projection): 在关系上投影就是从选择出若干属性列组成新的关系
select name,password from test where id=1;# 此处相当于投影,是按字段,按列进行相关操作的
链接(join): 将不同的两个关系链接成一个关系
2 insert 语句
INSERT INTO table_name(key1,key2...) VALUES(vaule1,value2...);
向表中插入一行数据,自增字段,缺省字段,可为空字段可以不写INSERT INTO table_name SELECT ...;
将SELECT 查询的结果插入到表中
INSERT INTO table_name(key1,key2,...) VALUES(value1,value2,...) ON DUPLICATE KEY UPDATE key1=value1...;
如果主键冲突,唯一键冲突就执行update后面的设置,这条语句的意思是,主键不是在新增记录,主键就在更新部分字段。
INSERT IGNORE INTO table_name(key1,key2,...) VALUES(value1,value2,...);
如果主键冲突,唯一键冲突就忽略错误,返回一个警告,并回滚。
3 update 语句
UPDATE [IGNORE] table_name SET col_name1=expr1[,col_name2=expr2...] [WHERE where_defintion] IGNORE(此处的含义和上述相同)
UPDATE reg SET name='1234' WHERE id=5
UPDATE 若不加where则会导致全部修改,某种情况下可能会导致严重的问题
4 delete 语句
DELETE [IGNORE] FROM table_name [WHERE where_defintion]
删除符合条件的记录
4 select语句
SELECT [DISTINCT] select_expr,... [FROM tanle_references] [ WHERE where_defintion] [GROUP BY {col_name | expr | position} [ASC | DESC],... [WITH ROLLUP]] [HAVING where_definition] [ORDER BU {col_name | expr | position} [ ASC | DESC ],...] [LIMIT {[offset,]row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]
中括号中代表可选
最后面的是排他锁和共享锁FOR UPDATE 会把进行写锁定,这是排他锁
1 简单查询
select 10/5; # 算数计算
select now(); # 查询当前时间
select * from employees; # 查询该表中的所有数据
2 字符串合并查询
CONCAT(str1,str2,str3)
select emp_no,last_name from employees; # 只显示两列
select emp_no,CONCAT(last_name," ",last_name) from employees; # 使用CONCAT() 将多个字符串进行合并
3 AS 别名定义
select emp_no as no,CONCAT(first_name," ",last_name) as name from employees as emp;
4 LIMIT 限定返回的条数,常用于分页
select * from employees LIMIT 2; # 显示前两行数据
select * from employees LIMIT 2 offset 4; # 从第四行开始,显示下面的两行数据,默认是从第0行还是的,
select * from employees LIMIT 2,4; # 此处表示偏移为2,显示4行
5 where 字句
运算符 | 描述 |
---|---|
= | 等于 |
<> | 不等于 |
>,<,>=,<= | 大于,小于,大于等于,小于等于 |
BETWEEN | 在某个范围之间,between a and b 等价与 [a,b] a到b的闭区间 |
LIKE | 字符串模式匹配,% 表示任意多个字符,_表示一个字符 |
IN | 指定针对某列的多个可能值 |
AND | 与 |
OR | 或 |
注意: 如果很多表达式需要使用AND,OR 计算逻辑表达式的值时,由于有结合律的问题,建议使用小括号来避免产生错误。
SELECT * from employees WHERE emp_no < 10015 and last_name like 'P%';
SELECT * from employees WHERE emp_no BETWEEN 10010 AND 10015 AND last_name like 'P%';
SELECT * from employees WHERE emp_no in (10001,10002,10010);
6 Order BY 字句
对查询结果进行排序,可以是升序,降序 DESC ,默认是升序
SELECT * from employees ORDER BY emp_no DESC ;
SELECT * from employees ORDER BY gender,emp_no;
SELECT * from employees ORDER BY emp_no desc,gender; # 一个降,另一个升
7 DISINCT 不返回重复记录
select DISTINCT dept_no from dept_emp;
select DISTINCT dept_no,emp_no from dept_emp; # 两个联合不重复
8 聚合数据
函数 | 描述 |
---|---|
COUNT(expr) 返回记录中的数目,如果指定列,则返回非NULL的行数 | |
COUNT(DISTINCT expr,[expr...]) | 返回不重复的非NULL 值的行数 |
AVG([DISTINCT expr]) | 返回平均值,返回不同值的平均值 |
MAX(expr),MIN(expr) | 最大最,最小值 |
SUM([DISTINCT] expr) | 求和,DISTINCT 返回不同值的求和 |
SELECT COUNT(DISTINCT emp_no),AVG(emp_no),MAX(emp_no),MIN(emp_no),SUM(emp_no) from employees;
SELECT COUNT(DISTINCT emp_no),AVG(emp_no),MAX(emp_no),MIN(emp_no),SUM(emp_no) from employees WHERE emp_no>10025;
9 分组查询
使用 GROUP BY 字句,如果有条件,使用Having子句过滤分组,聚合过的结果。默认聚合后只显示第一个。
-- 简单的分组查询
SELECT COUNT(*),sum(salary) FROM test.salaries GROUP BY emp_no;
-- 聚合分组查询,显示两个相同的部分
SELECT emp_no,sum(salary),count(*),max(salary),min(salary) from test.salaries GROUP BY emp_no,from_date;
SELECT emp_no,sum(salary),count(*),max(salary),min(salary) from test.salaries GROUP BY emp_no HAVING emp_no >10007;
结果如下
执行顺序:先是from后面的内容,其次是where过滤,后面是group by 分组,后面是having过滤,最后是order by 排序
10 子查询
子查询: 查询语句可以嵌套,内部查询就是子查询
子查询必须在一组小括号中
子查询中不能使用order by;
SELECT * FROM employees WHERE emp_no in (SELECT emp_no FROM employees WHERE emp_no>10020) ORDER BY emp_no;
SELECT emp.emp_no,emp.first_name FROM (SELECT * FROM employees WHERE emp_no > 10010) AS emp WHERE emp.emp_no < 10015 ORDER BY emp_no DESC;
-- IN后面跟单列是比较合适的,子查询是有意义的,内层选择只需要对使用的字段进行显示即可
SELECT * FROM employees WHERE emp_no IN (SELECT emp_no FROM employees WHERE emp_no > 10025 ) ORDER BY emp_no DESC
-- 子查询最好的使用方式
SELECT * FROM (SELECT emp_no,first_name,gender FROM employees WHERE emp_no > 10025) AS emp WHERE emp.emp_no < 10030 ORDER BY emp_no Desc;
11 连接 join
连接 join
交叉连接 cross join
笛卡尔乘积,全部交叉
在MySQL中,CROSS JOIN 从语法上和INNER JOIN 等同
1 交叉连接 CROSS JOIN ,及笛卡尔乘积,全部交叉
SELECT * FROM employees CROSS JOIN dept_manager
每一个结果分别和另一个结果集的所有数据相乘得到的乘机。
此种连接在生产环境中基本上是被废弃的,不用的
2 内连接 inner join ,省略为 join
等值连接,只选择某些filed相等的元组(行),使用ON 限定关联的结果
自然连接,特殊的等值连接,会过滤掉重复的行,用的少
等值连接
-- 此种方式由于没有配置ON,因此其值和交叉连接结果相同
SELECT * FROM employees INNER JOIN dept_manager;
-- 此处会选择两个表中相同字段相同部分呈现出来,并将两张表中相同的字段重复显示出来
SELECT * FROM employees JOIN salaries ON employees.emp_no=salaries.emp_no
其只显示等值的链接,对于在任何一张表中不存在的都不会显示
自然连接
-- 此处会选择两个表中相同字段相同部分呈现出来,并去除两张表中的相同字段的列,但某种情况下两张表中的含义相同的字段并非名称相同,因此不一定会使用到
SELECT * FROM employees NATURAL JOIN salaries;
3 外连接 outer join
左外连接
左链接: 左表的所有行都得有,左表和右表对不上的行也是需要显示的,右表中的数据有没有无所谓。
SELECT * from dept_emp LEFT JOIN departments on departments.dept_no=dept_emp.dept_no;
左表中加入了31号员工,未加入到任何部门,但在部门表中加入了管理部,此处未显示。
默认是以左表为主的,右表中的数据全不全无关
右外连接
右表中的40行在左表中全部都能找到,所以显示的是全部,视角在右表
SELECT * from employees RIGHT JOIN salaries on employees.emp_no=salaries.emp_no;
此处是等值关系,和具体的行没有关系
此处未加入部门的31号员工也未出现在此表中。而管理部出现在词表中
12 自连接
表自己和自己链接
SELECT * FROM employees as manager,employees as worker WHERE manager.emp_no=worker.emp_no and worker.emp_no=10010;
SELECT * FROM employees manager INNER JOIN employees worker ON manager.emp_no=worker.emp_no WHERE worker.emp_no=10010;
第一种方式写着简单,可以使用第一种方式进行处理,若需要特别的左链接或右链接时建议使用第二种方式
通过查询创建工具方式创建
三 MySQL事务
1 概述和属性
1 概述
事务Transaction
InnoDB 引擎,支持事务
事务,由若干条语句组成,指的是要做的一系列操作。
2 属性
关系型数据库中支持事务,必须支持其四种属性(ACID)
特性 | 描述 |
---|---|
原子性(atomicity) | 一个事务是不可分割的工作单位,事务中包括所有操作要么全部做完,要么什么都不做 |
一致性(consistency) 事务必须是使数据库从一个一致性状态变换到另一个一致性状态,一致性与原子性是紧密相关的 | |
隔离性(isolation) | 一个事务的执行不能被其他事务干扰,及一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰 |
持久性(durability) | 持久性也成为永久性(permanence),指一个事务一旦提交,它对数据库中的数据改变也就应该是永久性的,接下来的其他操作或者故障不应该对其有任何影响 |
3 具体理解
原子性: 要求事务中所有的操作,不可分割,不能做了一部分操作,剩下一部分操作。
一致性:多个事务并行执行的结果,应该和事务排队执行的结果一致,如果事务的并发执行和多线程读写共享资源一样不可预期,就不能保证一致性
隔离性:多个事务访问共享的数据了,应该互相不干扰,隔离性,指的是究竟在一个事务处理期间,其他事务能不能访问的问题
持久性:较好的理解,就是事务提交后,数据不能丢失。
2 事务的隔离级别
1 隔离性不好带来的问题
1 更新丢失 lost update
事务A 和事务B,更新同一个数据,都读取了初始值100,A要减10,B要加100,A减去10之后是90,B加100后是200,若A先写入,则B读取到的是100,而实际的结果已经是90了,而B使用100计算的结果是200,则此时便覆盖了A的90,将原本的190变成了200.
2 脏读 (读取到了中间状态)
事务A和事务B,事务B读取到事务A未提交的数据(这个数据可能是一个中间值,也可能是事物A回滚的值),只要读取到了这个被修改的数据就是脏读,只要没有提交,就是没有落地,就是脏数据,若中间出现了状态,回滚,则这个中间状态的数据也是脏数据。
3 不可重复读 (unrepeatable read) 同一条记录的修改
事务A 在同一个事务中执行了相同两次的查询语句,得到了不同的结果,不能保证同一条查询语句重复读相同的结果就是不可重复读。
例如: 事务A查询了一次后,事务B修改了数据,事务A又查询了一次,发现数据不一致了。
注意: 脏读是可以读取到相同的数据,但是读取到的是一个未提交的数据,不是提交的最终结果
4 幻读(phantom read) (增加了数据的不可重复读)
事务A中同一个查询要进行多次,事务B插入的数据,导致A返回不同的结果集,如同幻觉,就是幻读
数据集有记录增加了,可以看做是增加了记录的不可重复度
2 事务的隔离级别
针对上述问题,提出了4中事务的隔离级别,如下
隔离级别 | 描述 |
---|---|
READ UNCOMMITTED | 读取到未提交的数据 |
READ COMMITTED | 读已经提交的数据 |
REPEATABLE READ | 可重复读,MySQL的默认隔离级别 |
SERIALIZABLE | 可串行化,事务键完全隔离,事务不能并发,只能串行化执行 |
隔离级别越高,串行化越高,数据库执行效率越低,隔离级别越低,并行度越高,性能越高
隔离级别越高,当前事物处理的中间结果对其他事务不可见程度越高,
SERIALIZABLE:串行化能解决所有问题,但带来的确是效率极其低下。
REPEATABLE READ:事务A中同一条查询语句返回同样的结果,就是可以重复复读取数据了,解决的方式有:
1 对select的数据加锁,不允许其他事务删除,修改操作
2 第一次select的时候,对最后一次确切提交的事务的结果进行快照
但上述方式不能解决幻读READ COMMITTED:在事务中,每次select可以读取到别的事务刚提交成功的数据,因为读到的是提交后的数据,解决了脏读,但是不能解决不可重复读的问题
READ UNCOMMITTED:能读取到别的事务还没有提交的数据,完全没有隔离性可言,出现了脏读
3 设置会话或者全局的隔离级别
-- 设置全局或会话级别的隔离级别
SET [SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
-- 查询隔离级别
SELECT @@global.tx_isolation;
SELECT @@tx_isolation;
4 事务语法
START TRANSACTION 或 BEGIN 开始一个事务,START TRANSACTION 是标准的SQL的语法
使用COMMIT提交事务后,变更成永久变更。
ROLLBACK 可以在提交事务之前,回滚变更,事务中的操作就如同没有发生过一样
SET AUTOCOMMIT 语句可以禁用或启用默认的autocommit模式,用于当前链接,SET AUTOCOMMIT=0 表示禁用自动提交事务,如果开启自动提交,如果有一个修改表的语句执行后,会立即把更新存储到磁盘上。
开发过程中自动提交一般都是关闭的,一般的是一次提交多次修改的值。
测试重复读
新建一张表,如下
CREATE TABLE `t` (
`id` int(11) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
mysql> desc t;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| username | varchar(255) | YES | | NULL | |
| password | varchar(255) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
查看事务的隔离级别
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
在窗口1关闭自动提交
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
在窗口1 查询t表中内容
mysql> select * from t;
Empty set (0.00 sec)
在窗口2中直接进行插入操作并查看
mysql> insert into t value(1,'admin','admin');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
在窗口1 中再次查询,无结果,再次进行提交后查询,则产生了结果,此处表明解决了重复读问题。
mysql> select * from t;
Empty set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
读已提交测试
修改窗口1 的级别为读提交,并提交此次修改
mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
在窗口2 进行插入
mysql> insert into t value(2,'root','root');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
| 2 | root | root |
+------+----------+----------+
2 rows in set (0.00 sec)
在窗口1 进行查看,修改提交的数据可以看到,此处表明修改成读提交成功
mysql> select * from t;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
| 2 | root | root |
+------+----------+----------+
2 rows in set (0.00 sec)
3 其他属性
1 数据仓库和数据库的区别
本质上说没有区别,都是存放数据的得房,但是数据库关注的是数据的持久化,数据的关系,为业务提供系统支持,事务支持,数据仓库存储数据是为了分析或者发掘而设计的表结构,可以存储海量数。
数据库存储在线交易数据OLTP;数据仓库存储历史数据用于分析OLAP。
数据库支持在线业务,需要频繁增删改查,数据仓库一般囤积历史数据支持用于分析的SQL,一般不建议删改。
2 游标
操作查询的结果集的一种方法
可以将游标当做是一个指针,指向结果集中的某一行。
3 存储过程,触发器
存储过程(Stored Procedure),数据库系统中,一段完成特定功能的SQL语句,编写成类似函数的方式,可以传递参数并调用,支持流程控制语句。
触发器(Tirgger),由事件触发的特殊的存储过程,例如insert时数据触发
触发器虽然功能强大,但基本很少使用了