MySQL数据库学习日志(五):数据库事务 DCL

MySQL数据库学习日志(五):数据库事务 DCL

  • MySQL数据库学习日志(五):数据库事务 DCL
    • 数据库事务
      • (一)什么是数据库事务
      • (二)事务的目的
      • (三)事务特性
      • (四)操作事务
        • 1. 自动提交事务
        • 2. 手动提交事务
        • 3. 事务原理
      • (五)事务的并发异常
      • (六)隔离级别
        • 1. 隔离级别的查看和修改
        • 2. 隔离级别应用
          • 以Read Uncommitted测试为例
          • 1)测试脏读
          • 2)测试不可重复读
          • 3)测试幻读
          • 4)测试丢失更新
    • DCL
      • (一)创建用户
      • (二)授权用户
      • (三)查看权限
      • (四)删除用户
      • (五)修改管理员的密码
      • (六)修改普通用户密码
    • end

数据库事务

(一)什么是数据库事务

数据库事务是访问并可能操作各种数据项的一个数据库操作(包括读、写)序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

例如:银行转账。核心操作包括更新一个账户减去转账金额,更新另一个账户加上转账金额,要求要同时成功或同时失败。

(二)事务的目的

  1. 为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。

  2. 当多个应用程序在并发方法数据库时,可以再这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

总结:事务的目的就是要提供3种方法:

  1. 失败恢复方法。
  2. 保持一致性的方法。
  3. 操作隔离的方法。

成功情况下

能将数据从一种状态变为另一种状态,并能够持久化。

异常情况下

  1. 能将数据恢复到正常状态。

  2. 要能保证一致性,包含数据的一致性和约束的一致性。

并发情况下

并发的操作之间不能产生相互影响。

(三)事务特性

事务包括ACID四个特性,分别是原子性、一致性、隔离性、持久性。

原子性(Actomicity)

表示一个事务内的所有操作是一个整体,是一个不可分割的工作单位,要么全部成功,要么全部失败。

一致性(Consistency)

事务前后数据的完整性必须保持一致。

隔离性(Isolation)

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

持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

(四)操作事务

在数据库中,一个事务可以由多条SQL语句组成,当然一个事务中也可以只包含一条SQL语句。

MYSQL中可以有两种方式进行事务的操作:

  1. 自动提交事务。
  2. 手动提交事务。
1. 自动提交事务

MySQL的每一条DML(增删改)语句都是一个单独的事务,MySQL默认情况下,在执行每条语句时都会自动开启一个事务,执行完毕自动提交事务。

MySQL数据库学习日志(五):数据库事务 DCL_第1张图片

当语句执行完成后,数据库中添加了数据。

MySQL数据库学习日志(五):数据库事务 DCL_第2张图片

2. 手动提交事务

事务有关的SQL语句
MySQL数据库学习日志(五):数据库事务 DCL_第3张图片

示例

start transaction; -- 开启事务
update emp set name='李四' where id=10; -- 更新数据

-- 在没有提交事务时,数据库中的数据不会真正的发生变化

MySQL数据库学习日志(五):数据库事务 DCL_第4张图片

commit;-- 提交事务
-- 事务提交后,数据库中的数据才会真正的变化

MySQL数据库学习日志(五):数据库事务 DCL_第5张图片

示例2

start transaction; --开启事务
update emp set name='王五' where id=10; -- 更新数据
-- 如果不提交事务,而是回滚事务,数据库中的数据将不会变化
rollback;

MySQL数据库学习日志(五):数据库事务 DCL_第6张图片

3. 事务原理

事务开启之后, 所有的操作都会临时保存到事务日志, 事务日志只有在得到commit命令才会同步到数据表中,其他任何情况都会清空事务日志(rollback,断开连接)

MySQL数据库学习日志(五):数据库事务 DCL_第7张图片

(五)事务的并发异常

在事务并发操作时(例如多个客户端来操作同一个数据库中的同一张表)。可能会出现如下的问题。

MySQL数据库学习日志(五):数据库事务 DCL_第8张图片

当然这些并发的异常可以说是由数据库的隔离级别引起的,或者说通过调整数据库的隔离级别可以防止以上并发异常的发生。

(六)隔离级别

数据库的事务隔离级别主要包括:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable)。隔离级别越高,数据库的效率就越低。

MySQL数据库InnoDB存储引擎(默认)的默认隔离级别是Repeatable Read

SQL sever默认系统事务隔离级别是read committed

Oracle数据库默认的隔离级别是Read Committed

各种隔离级别能解决哪些并发异常

MySQL数据库学习日志(五):数据库事务 DCL_第9张图片

1. 隔离级别的查看和修改

MySQL8 以前版本

查看

select @@session.tx_isolation

修改

set @@session.tx_isolation=’隔离级别’

MySQL8

查看

select @@transaction_isolation

修改

set session transaction isolation level 隔离级别

示例

MySQL数据库学习日志(五):数据库事务 DCL_第10张图片

MySQL数据库学习日志(五):数据库事务 DCL_第11张图片

当然,修改隔离级别,只是修改当前会话的隔离级别。如果打开另外一个会话查看,隔离级别没有改变。

2. 隔离级别应用

准备数据

create database tx character set utf8;
create table stu(
     id int primary key auto_increment,
	 name varchar(20),
	 age int
);
insert into stu values(null,'张三',20);
insert into stu values(null,'李四',21);
insert into stu values(null,'王五',22);
insert into stu values(null,'赵六',23);
insert into stu values(null,'小王',24);

MySQL数据库学习日志(五):数据库事务 DCL_第12张图片

以Read Uncommitted测试为例

(理解5种事务并发异常)

1)测试脏读

在Navicat中开启两个命令窗口,每一个窗口就相当于一个线程。

MySQL数据库学习日志(五):数据库事务 DCL_第13张图片

MySQL数据库学习日志(五):数据库事务 DCL_第14张图片

1、把两个命令窗口的隔离级别都修改成 Read Uncommitted

set session transaction isolation level read uncommitted

MySQL数据库学习日志(五):数据库事务 DCL_第15张图片

2、在窗口1开启事务,更新id为1的年龄为100,不提交事务。

start transaction;
update stu set age=100 where id=1;

MySQL数据库学习日志(五):数据库事务 DCL_第16张图片

3、在命令窗口2中,查看id为1的数据

start transaction;
select * from stu where id=1;

MySQL数据库学习日志(五):数据库事务 DCL_第17张图片

4、如果窗口1回滚,窗口2读到的数据又会发生变化

在这里插入图片描述

MySQL数据库学习日志(五):数据库事务 DCL_第18张图片

2)测试不可重复读

1、窗口1开启事务查询id为1的数据

start transaction;
select * from stu where id=1;

MySQL数据库学习日志(五):数据库事务 DCL_第19张图片

2、窗口2开启事务,更新id为1的age为100

start transaction;
update stu set age=100 where id=1;
commit;

MySQL数据库学习日志(五):数据库事务 DCL_第20张图片

3、回到窗口1,还是在原来的事务中,查询id为1的数据

select * from stu where id=1;

MySQL数据库学习日志(五):数据库事务 DCL_第21张图片

3)测试幻读

1、在窗口1中开启事务,查询stu表的数据总条数

start transaction;
select count(*) from stu;

MySQL数据库学习日志(五):数据库事务 DCL_第22张图片

2、在窗口2中开启事务,插入一条新数据

start transaction;
insert into stu values(6,'王二小',30);
commit;

MySQL数据库学习日志(五):数据库事务 DCL_第23张图片

3、回到窗口1,还是在当前事务中,再次查询数据条数

select count(*) from stu;

MySQL数据库学习日志(五):数据库事务 DCL_第24张图片

4)测试丢失更新

关于丢失更新的说明

MySQL数据库学习日志(五):数据库事务 DCL_第25张图片

测试回滚丢失

1、窗口1和窗口2都开启事务,查询id为1的数据的信息

start transaction;
select * from stu where id=1;

MySQL数据库学习日志(五):数据库事务 DCL_第26张图片

2、窗口1更新id为1的age=age+1

update stu set age=age+1 where id=1;

在这里插入图片描述

操作成功!!!

3、窗口2更新id为1的age=age+2

update stu set age=age+2 where id=1;

会发现窗口2的更新会阻塞!这是因为在mysql数据库中,在窗口1更新这条数据没有提交时,对该条数据加锁了,导致窗口2无法更新这条数据。只有当窗口1提交时,窗口2的更新会自动执行。

窗口1:

commit;

窗口2:
在这里插入图片描述

4、窗口2回滚

rollback;

5、回到窗口1查询数据

select * from stu where id=1;

MySQL数据库学习日志(五):数据库事务 DCL_第27张图片

我们会发现,并没有出现我们预期的丢失更新的情况!

这是因为MySQL的锁引起的,无论使用哪种隔离级别都无法掩饰出丢失更新的情况!除非关闭MySQL的锁。

其余隔离级别测试同上


再放一下最后结论:

MySQL数据库学习日志(五):数据库事务 DCL_第28张图片

注意:MySQL在Repeatable Read的隔离级别下,也不存在幻读了。这是因为MySQL中采用了next-keygap-lock的机制的问题,这里不进行深入的探讨


DCL

简单了解即可(一般是DBA操作)

我们现在默认使用的都是root用户,超级管理员,拥有全部的权限。但是,一个公司里面的数据库服务器上面可能同时运行着很多个项目的数据库。所以,我们应该可以根据不同的项目建立不同的用户,分配不同的权限来管理和维护数据库。用户和权限的管理可以通过DCL(Data Control Language)来实现。

(一)创建用户

语法

CREATE USER '用户名'@ '主机名' IDENTIFIED BY '密码'
  -- 1、`用户名`:将创建的用户名
  -- 2、`主机名`:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符%
  -- 3、`密码`:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器

示例

-- user1用户只能在localhost这个IP登录mysql服务器
CREATE USER 'user1'@'localhost' IDENTIFIED BY '123';
-- user2用户可以在任何电脑上登录mysql服务器
CREATE USER 'user2'@'%' IDENTIFIED BY '123';
-- 使用新创建user1登录

MySQL数据库学习日志(五):数据库事务 DCL_第29张图片

(二)授权用户

用户创建之后,基本没什么权限!需要给用户授权。

MySQL数据库学习日志(五):数据库事务 DCL_第30张图片

语法

GRANT 权限1, 权限2... ON 数据库名.表名 TO '用户名'@'主机名';
-- 1、`GRANT` 授权关键字
-- 2、授予用户的权限,如`SELECT`,`INSERT`,`UPDATE`等。如果要授予所的权限则使用`ALL`
-- 3、 `数据库名.表名`:该用户可以操作哪个数据库的哪些表。如果要授予该用户对所有数据库和表的相应操作权限则可用表示,如`*.*`
-- 4、 `'用户名'@'主机名'`: 给哪个用户授权

示例1

-- 给user1用户分配对mydb5这个数据库操作的权限。
GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON mydb5.* TO 'user1'@'localhost';

注意要使用root用户进行授权

MySQL数据库学习日志(五):数据库事务 DCL_第31张图片

示例2

-- 给user2用户分配对所有数据库操作的权限。
GRANT ALL ON *.* TO 'user2'@'%';

MySQL数据库学习日志(五):数据库事务 DCL_第32张图片

(三)查看权限

语法

SHOW GRANTS FOR '用户名'@'主机名';

示例

-- 查看user1用户的权限
SHOW GRANTS FOR 'user1'@'localhost';

MySQL数据库学习日志(五):数据库事务 DCL_第33张图片

(四)删除用户

语法

DROP USER '用户名'@'主机名';

示例

-- 删除user2
DROP USER 'user2'@'localhost';

(五)修改管理员的密码

语法

mysqladmin -uroot -p password 新密码 -- 新密码不需要加上引号

示例

mysqladmin -uroot -p password 123456
输入老密码
-- 注意:要在未登录的情况下操作

(六)修改普通用户密码

语法

set password for '用户名'@'主机名' ='新密码';

示例

set password for 'user1'@'localhost' = '666666';
-- 注意:要在登录情况下操作

end


MySQL数据库学习日志(五):数据库事务 DCL_第34张图片

你可能感兴趣的:(数据库,mysql,数据库,sql)