事务的概念和特性
事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位
基本特性
原子性(Atomicity):事务中的操作要么全部成功,要么全部回退
一致性(Consistency):事务执行前后数据在逻辑上是一致的
隔离性(Isolation):保证事务在不受外部并发操作影响的独立环境下运行
持久性(Durability):事务执行完后(提交或回滚),对数据进行的更改将被保存,对数据的改变是永久的
事务的特性(ACID)
保证事务ACID特性是事务处理的任务
破坏事务ACID特性的因素
多个事务并行运行时,不同事务的操作交叉执行
数据库管理系统必须保证多个事务的交叉运行不影响这些事务的隔离性
事务在运行过程中被强行停止
数据库管理系统必须保证被强行终止的事务对数据库和其他事务没有任何影响
事务的基本操作
查看/设置事务提交方式
selete @@autocommit;
set @@autocommit=0;--设置为手动提交,默认为1
开启事务
start transaction;或begin;
提交事务
commit;
回滚事务
rollback;
事务的提交方式
事务的自动提交
MySQL的系统变量autocommit,用来设置是否自动提交事务,默认为“NO”,即为自动提交
默认情况下,如果不显示的使用start transaction或者begin语句开启事务,那么每一条语句都算是一个独立的事务,这种特性称为事务的自动提交
关闭自动提交功能
可以通过显示的使用start transaction或者begin语句来关闭自动提交的功能,也可以通过set autocommit=OFF语句来关闭自动提交的功能
这样关闭自动提交功能之后,写入的多条语句都属于同一个事务,直到显示的写出commit语句提交事务,或显示的写出rollback语句回滚事务
事务的隐式提交
当关闭自动提交功能之后,事务就不会进行自动提交了
但是输入一些特殊语句,会导致之前的事务提交,这种因为某些特殊的语句而导致事务提交的情况被称为隐式提交
会导致事务隐式提交的语句主要有:
定义或修改数据库对象的数据定义语句,如:create table, create view等
隐式的使用或修改mysql数据库中的表,如drop user, grant, revoke等语句
事务控制或关于锁定的语句,使用lock tables, unlock tables等关于锁定的语句
当在一个事务还没提交或者还没回滚时,又开启了另一个事务
保存点
保存点(savepoint)就是在事务对应的数据库语句中设置几个“点”,保证在调用rollback语句时可以指定回滚到那个点
定义保存点的语法格式
savepoint 保存点名称;
回滚到某个保存点语法
rollback to 保存点名称
删除保存点语法:
release savepoint 保存点名称;
并发执行可能引发的问题
并发事务所引发的问题指的是多个事务同时操作某个数据库或某张数据表时所英法的问题:脏读、不可重复读、和幻读
脏读:一个事务读到另一个事务没有提交的数据
不可重复读:一个事务先后读取同一条数据,但两次读取的数据不同,称为不可重复读
幻读:一个事务按照条件查询时没有读到数据行,但执行插入操作时,又发现数据行已存在,好像出现了幻影
事务的隔离级别
隔离级别:一个事务与其他事务的隔离程度
用于解决并发事务引发的问题
read uncommited(读未提交):时最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据
read commited(读已提交):保证一个事务提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据
repeattable read(可重复读):它除了保证一个事务不能被另外一个事务读取为提交的数据之外还避免了不可重发读情况的产生
serializable(串行读):花费最高代价但最可靠的事务隔离级别。事务被处理顺序执行,处理防止脏读,不可重复读之外还避免了幻读
事务隔离级别越高,数据越安全,性能越低。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
read uncommitted | √ | √ | √ |
read committed | × | √ | √ |
repeattable read(mysql默认) | × | × | √ |
serializable | × | × | × |
查看事务隔离级别
select @@transaction_isolation;
设置事务隔离级别
set [session|global] transaction isolation lebel
read uncommitted | read committed | repeatable read | serializable
mysql的锁机制(了解)
当多个事务同时修改同一数据时,只允许持有锁的事务修改该数据,其他事务只能“排队等待”,直到前一个事务释放器拥有的锁
按操作类型划分
锁是计算机协调多个进行或线程并发访问某一资源的机制(避免抢占)
读锁(共享锁):针对同一份数据,多个读操作可以同时进行,不会互相影响。不会自动加
写锁(排它锁):当前操作没有完成之前,它会阻断其他写锁和读锁。增删改查,会自动加排他锁
按粒度划分
1.全局锁:锁定数据库中的所有表
典型应用场景是做全款的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。
2.表锁:操作时,会锁定整个表
MySQL各种存储引擎都支持表锁(MyISAM、InnoDB、Memory、BDB)。
特点:加锁快,不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
不需要显示加锁,MyISAM引擎会自动在读写之前分别加读锁和写锁。
3.行锁:操作时,会锁定当前操作行(只有InnoDB存储引擎支持行锁。)
特点:加锁慢,会出现死锁;锁定粒度小,发生锁冲突的概率最低,并发度最高。
InnoDB共有七种类型的锁
1.共享/排它锁(Shared and Exclusive Locks)
共享锁(记为S锁),读取数据时加S锁;排他锁(记为X锁),修改数据时加X锁;共享锁之间不互斥,简记为:读读可以并行;排他锁与任何锁互斥,简记为:写读,写写不可以并行。
2.意向锁(Intention Locks)
InnoDB为了支持多粒度锁机制(multiplegranularity locking),即允许行级锁与表级锁共存,而引入了意向锁(intention locks)。
意向锁是指未来的某个时刻,事务可能要加共享/排它锁,先提前声明一个意向。
意向锁是一个表级别的锁(table-levellocking);意向锁又分为意向共享锁(简记为IS锁)和意向排它锁(简记为IX锁)。其中IS锁表示事务有意向对表中的某些行加共享S锁,IX锁表示事务有意向对表中的某些行加排它X锁。
加锁的语法格式如下:
select ... lock in sharemode; /*要设置IS锁;*/
select ... forupdate; /*要设置IX锁;*/
3.记录锁(Record Locks)
记录锁封锁索引记录,例如(其中id为主索引):
createtable lock_example(idsmallint(10),name varchar(20),primary key id)engine=innodb;
select* from lock_examplewhereid=1 for update;
这里需要先获取该表的意向排他锁(IX),再获取这行记录的排他锁,以阻止其他事务插入、更新、删除id=1的行数据。
4.间隙锁(Gap Locks)
间隙锁封锁索引记录中的间隔,或者第一条索引记录之前或最后一条索引索引记录之后的范围,例如:
select* from lock_example
whereid between 8 and 15
forupdate;
这个SQL语句会封锁区间(8,15),以阻止其他事务插入id位于该区间的记录。
间隙锁的主要目的就是为了防止其他事务在间隔中插入数据,以导致“不可重复读”。
5.临键锁(Next-key Locks)
临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
默认情况下,InnoDB使用Next-KeyLock来锁定记录。但当查询的索引含有唯一属性的时候,Next-Key Lock会进行优化,将其降级为Record Lock,即仅锁住索引本身,不是范围。
例如:事务A执行如下语句,未提交:
select * from lock_example where id = 20for update;
事务B开始,执行如下语句,会阻塞:
insert into lock_examplevalues('zhang',15);
事务A执行查询语句之后,默认给id=20这条记录加上了Next-KeyLock,所以事务B插入[10,30]区间之内的记录都会阻塞。
临键锁的主要目的,也是为了避免“幻影现象”。
6.插入意向锁(Insert Intention Locks)
对已有数据行的修改与删除,必须加强排他锁,那么对于数据的插入,不必加这么强的锁来实施互斥,只需插入意向锁即可。
插入意向锁,是间隙锁(GapLocks)的一种,是专门针对INSERT操作的。多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
例如:事务A先执行,在10与20两条记录中插入了一行,还未提交:
insert into t values(11, xxx);
事务B后执行,也在10与20两条记录中插入了一行:
insert into t values(12, xxx);
因为是插入操作,虽然是插入同一个区间,但是插入的记录并不冲突,所以使用的是插入意向锁,此处A事务并不会阻塞B事务。
7.自增锁(Auto-inc Locks)
自增锁是一种特殊的表级别锁,专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行是连续的主键值。
例如:事务A先执行,还未提交:
insert into t(name) values(xxx);
事务B后执行:
insert into t(name) values(xxx);
此时事务B插入操作会阻塞,直到事务A提交。