一、事务的介绍
事务:表示操作集合,不可分割,要么全部成功,要么全部失败
事务的开始取决于一个DML语句
事务的结束:
1、正常的commit或者rollback
2、自动提交,一般情况下进行关闭操作,效率太低
3、用户关闭会话之后会自动提交事务
4、系统崩溃或断电的时候会回滚事务
二、事务的四个特性(ACID)
1、原子性:一个操作集合(事务)要么全部成功,要么全部失败
2、一致性:保证数据的一致性,经过n多个操作之后,数据的状态不会改变(转账时总金额不会改变)
3、隔离性:各个事务之间不会产生影响。严格的隔离性会降低效率,某些情况下会降低隔离级别来提高效率
4、持久性:所有数据的修改都必须持久化到存储介质,不会因为程序的关闭而导致数据的丢失
注意:数据库所有特性中都是为了保证数据的一致性
三、锁的机制
为了解决在并发访问的时候,数据不一致的问题,需要给数据加锁
加锁的同时需要考虑‘粒度’的问题:
操作对象有:①数据库
②表
③行
一般情况下,锁的粒度越小,效率越高,粒度越大,效率越低
三、事务的隔离级别
利用mysql数据库命令行进行模拟:
①开启两个命令窗口
②关闭事务自动提交:set autocommit = 0(select @@autocommit查看事务是否自动提交,1为开启,0为关闭)
注意:autocommit在不考虑隔离级别的时候主要针对增删改操作,不针对表创建
在一个事务中创建表,即使没有commit,另一个事务中也可以找到对应表名
③准备测试数据
创建数据库:create database tran;
切换数据库(两个窗口都执行):use tran;
创建表:create table psn(id int primary key,name varchar(10)) engine=innodb;
插入数据:insert into psn values(1,'zhangsan');
insert into psn values(2,'lisi');
insert into psn values(3,'wangwu');
commit;
1、读未提交:会造成脏读
A:set session transaction isolation level read uncommitted.
设置当前会话 事务 隔离 级别 读未提交
start transaction; 开启一项新的事务
B:set session transaction isolation level read uncommitted.
start transaction;
A:select * from psn;
B:select * from psn; 这时两个窗口数据一致
A:update psn set name = 'x'
A:select * from psn; 发现数据已经修改
B:select * from psn; 发现数据已经修改,但此时A窗口中事务未提交
解释:A事务并未提交事务,但此时B窗口已经读到未提交的事务
2、读已提交:会造成不可重复读
A:set session transaction isolation level read committed.
设置当前会话 事务 隔离 级别 读已提交
start transaction; 开启一项新的事务
B:set session transaction isolation level read committed.
start transaction;
A:select * from psn;
B:select * from psn; 这时两个窗口数据一致
A:update psn set name = 'y' where id = 1; 此时A窗口中数据发生改变
B:select * from psn; 此时B窗口中数据未发生改变,屏蔽了脏读的情况
A:commit;
B:select * from psn; 此时数据已经改变
解释:在B窗口内,出现了情况不相同的两种数据情况。
相当于你去银行取钱,在插卡的时间内,10点显示你的余额有1000,10点05分显示你的余额有500,在这期间你的银行卡是未拔出的。这是不合理的。
若此时B窗口在提交事务后进行查询,则会显示正常数据。
3、可重复读:会造成幻读,只在插入和删除的时候会产生
A:set session transaction isolation level repeatable read;
设置当前会话 事务 隔离 级别 可重复读
start transaction; 开启一项新的事务
B:set session transaction isolation level repeatable read;
start transaction;
A:select * from psn;
B:select * from psn; 这时两个窗口数据一致
A:update psn set name = 'y' where id = 2; 此时A窗口中数据发生改变
commit;
B:select * from psn; 此时B窗口中数据未发生改变,屏蔽了不可重复读的情况
commit;
A:start transation;
B:start transation;
A:select * from psn;
B:select * from psn; 此时数据一致性
A:insert into psn values(4,'e');
commit;
B:select * from psn; 发现无id为4的数据
B:insert into psn values(4,'e'); 在B窗口中执行A窗口中的插入语句,报错主键重复
解释:在B窗口中执行A窗口中的插入语句,报错主键重复,说明此时B窗口中已经查到id为4的数据,但未显示
4、序列化