事务
事务的基本概念
事务是作为单个逻辑单元所执行的一系列操作,如:新建一个数据库或表格,对表数据的插入、更新、删除,执行一个存储过程或函数等,都是一个事务。
事务控制
事务的控制有两种方法:
- 隐式事务
隐式事务是不用管理员手动写的,是指单独的insert、update、delete默认是隐式事务,由系统自动提交。 - 显式事务
显式事务就不是由系统自动提交的,是需要用户手动提交的。
关闭隐式事务自动提交
-
查看自动提交变量的状态
show variables like 'autocommit'; #隐式事务自动提交是由一个变量来控制的。 #它默认是打开的。
-
通过设置自动提交变量的值为off或者0来关闭自动提交。
#关闭自动提交 set autocommit = off; #0 #打开自动提交 set autocommit = on; #1
回滚
没有设置提交的数据并没有从数据表中真实删除,就是因为数据没有自动提交,数据只是从查询结果集中删除了,此时我们打开另外一个命令列界面就可以查询出没提交之前的数据。
所以没有自动提交的数据是可以回滚(撤销)的。
回滚关键字:rollback
提交
确认事务,将没有自动提交的事务确认提交,也就是手动提交。
提交事务关键字:commit
确认提交后回滚就没有用了
显式事务
- 开启显示事务
start transaction
#在后面的语句里,暂停自动提交
-
事务的显示控制
set autocommit = 1; # 确认开启自动提交 start transaction; # 开始显式事务 delete from orders where id = 2; # 删除数据 # 是否删除? rollback; # 回滚(不删除) commit; # 提交(确认删除) # 显示控制就相当于删除文件时会提示“是否确认删除”,需要手动提交。
事务的隔离
在数据库的使用过程中,无法避免的会有多个用户同时使用一个数据表的情况,所以就有了事务并发控制的概念,也就是每个用户的事务要隔离开来。
- 查看当前隔离级别
隔离级别有两种:
-
会话级别的隔离(当前连接有效):
select @@session.tx_isolation;
它是由一个会话变量tx_isolation保存的,MySQL默认为’REPEATABLE-READ’,可重读。
-
全局级别的隔离(当前服务有效):
select @@global.tx_isolation;
它是由一个全局变量tx_isolation保存的,MySQL默认为’repeatable-read’,可重读。
设置当前隔离级别
- 会话级、全局级:
#设置当前会话隔离级别为读未提交。 set [global] session transaction isolation level read uncommitted; # 设置当前会话隔离级别为读提交。 set [global] session transaction isolation level read committed; # 设置当前会话隔离级别为可重读(默认的)。 set [global] session transaction isolation level repeatable read; # 设置当前会话隔离级别为串行化读。 set [global] session transaction isolation level serializable;
测试隔离
这里以会话级别的隔离为例子。
首先打开两个cmd命令界面,进入Mysql,打开数据库。
#测试读未提交(read uncommitted)
#例如:首先设置两个会话的隔离级别都为读未提交
set session transaction isolation level read uncommitted;
#在第一个连接中开启显式事务,修改表中的数据
start transaction; # 开始显式事务
update test set age = 20 where id = 1; # 修改表中数据
#然后在另一个连接中查询相应的记录 # 查看读未提交的数据
select * from test where id = 1; # 这里就产生了脏读
#回到第一个连接中回滚此事务
rollback; # 回滚事务
#最后在另一个连接中查询相应的记录
select * from test where id = 1; # 查看回滚后的数据
#测试可重读(repeatable read)
#例如:首先设置两个会话的隔离级别都为可重读
set session transaction isolation level repeatable read;
#在第一个连接中开启显式事务,查找表中的数据
start transaction; # 开始显式事务
select * from test where id = 1; # 查询出来的是原数据
#然后在另一个连接中修改相应的记录 # 修改数据
update test set age = 24 where id = 1; # 修改表中数据
#回到第一个连接查询记录
select * from test where id = 1; # 查询出来的是原数据
#最后提交事件:commit; 并再查询一遍记录
select * from test where id = 1; # 现在查询的就是新数据
##测试串行化读(serializable)
#例如:首先设置两个会话的隔离级别为串行化读
set session transaction isolation level serializable;
##查看当前隔离级别:select @@session.tx_isolation;
##在第一个连接中开启显式事务,修改表中的数据
start transaction; # 开始显式事务
update test set age = 20 where id = 1; # 修改表中数据
#然后在另一个连接中开启显示事务,查询相应的记录
select * from test where id = 1; # 查询没有反映
#回到第一个连接中提交事务:commit;
# 提交事务后另一个连接中才能查询出结果
锁
锁的基本概念
锁是用于解决资源的共享使用的一种机制
只有在用户写时才需要加锁,用于保证数据的一致性。
锁的类型
MySQL中不同的存储引擎所使用的锁是不同的。
- 表级锁
一个用户在访问一个表时,对整张表进行加锁,另外一个用户就访问不了这个表了。多个用户不能同时使用一张表。
MyISAM和MEMORY存储引擎采用表级锁。 - 页面锁
将表分成许多页,只对某一页加锁。页面锁可以精确到表的一部分,只锁表里的一部分数据。
BDB存储引擎采用页面锁。
而innodb存储引擎采用表级锁和行级锁,默认是行级锁。
读锁和写锁
- read读锁(共享锁)
事务N在A对象上加了共享锁S,其他事务就不可修改表,但可以查询A,并且也可以加共享锁。 - write写锁(排他锁)
事务N在A对象上加了排他锁X,其他事务不可读不可写,也不可以加锁。
用户读数据时自动加read锁,修改数据自动加write锁。
-
加锁
Lock tables 表名 锁类型; # 锁类型:read/write
-
解锁
unlock tables;