TCL:数据库事务
TCL:数据库事务
介绍
TCL
Transaction Control Language 事务控制语言
事务
- 由一个或一组sql语句组成的一个执行单元,整个单独单元作为一个不可分割的整体。这个执行单元要么全部执行,要么全部不执行。
即如果单元中某条语句一旦执行失败或产生错误,整个单元将会回滚。所有收到影响的数据将返回到事务开始以前的状态;
如果单元中的所有SQL语句执行成功,则事务被顺利执行。
- 在mysql中的数据用各种不同的技术存储在文件或内存中;
- 通过show engines; 查看mysql支持的存储引擎;
- 在mysql中用的最多的存储引擎有:innodb, myisam, memory等;innodb支持事务,myisam,memory不支持事务。
- 事务主要用于处理操作量大,复杂度高的数据
- 事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行
- 事务用来管理insert,update,delete语句
事务的ACID属性
一般来说,事务是必须满足4个条件(ACID): Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)
原子性
事务是一个不可分割的工作单位。一组事务,要么成功;要么撤回。
一致性
事务必须使数据库从一个一致性状态变换到另一个一致性状态。
隔离性
事务独立运行,一个事务的执行不能被其他事务干扰;一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
可靠性
一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit选项 决定什么时候吧事务保存到日志里。
事务的创建
- 隐式事务: 事务没有明显的开启和结束标记, 比如insert, update, delete语句
- 显示事务: 事务有明显的开启和结束标记, 前提必须先设置自动提交功能为禁用
- set autocommit=0;
- show variables like 'autocommit';
/* 开启事务 步骤1 SET AUTOCOMMIT=0; START TRANSACTION; # 可选 步骤2:编写事务中的sql语句(select, insert, update, delete) 语句 1; 语句 2; ... 结束事务 commit; 提交事务 rollback; 回滚 */
事务隔离级别
并发问题
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:
-
- 脏读:对于两个事务T1,T2; T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的。
- 不可重复读: 对于两个事务T1, T2读取了同一个字段,然后T2更新了该字段之后,T1再次读取同一个字段,值就不一样了。同一个事务T1中,两次读取数据值不一样
- 幻读: 对于两个事务T1,T2从一个表中读取数据,然后T2在该表中插入了一些新的行,T1再次读取同一个表,就会多出几行。
数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使他们不会相互影响,避免各种并发问题。
隔离级别
一个事务与其他事务隔离的程度称为隔离级别。数据库提供了4中事务隔离级别。
隔离级别 | 描述 | 出现问题 |
READ UNCOMMITTED 读未提交数据 |
允许事务读取未被其他事务提交的变更,也叫脏读; |
脏读、不可重复读、幻读 |
READ COMMITED 读已提交数据 |
允许事务读取已经被其他事务提交的更, 可以避免脏读, |
不可重复读、幻读 |
REPEATABLE READ 可重复读 |
确保事务可以多次从一个字段中读取相同的值,在这个事务期间,其他事务对这个字段进行更新对这个事务无影响 可以避免脏读和不可重复读 |
幻读 |
SERIALIZABLE 串行化 |
确保事务可以从一个表中读取相同的行。 在这个事务持续期间,禁止其他事务对该表执行插入,更新和删除操作,
|
性能十分低下 |
数据库对隔离级别的支持
- Oracle支持2种事务隔离级别:READ commited, SERIALIZABLE。 默认使用READ COMMITTED
- MySql支持4中事务隔离级别。默认使用REPEATABLE READ。
- 每启动一个mysql程序,就会获得一个单独的数据库连接,每个数据库连接都有一个全局变量@@tx_isolation,表示当前事务隔离级别
- 查看隔离级别: select @@tx_isolation
- 设置MYSQL隔离级别: set session transaction isolation level read uncommitted;
- 设置数据库系统的全局的隔离级别: set global transaction isolation level read uncommitted;
回滚点
# savepoint set autocommit=0; start transaction; delete from student where id=2; savepoint a; # 设置保存点 delete from student where id=5; rollback to a; # 回滚到保存点
事务锁
为了解决事务隔离性问题,引入锁的概念,只有拿到锁的事务才可对数据库进行读写操作只有拿到锁的事务才可对数据库进行读写操作只有拿到锁的事务才可对数据库进行读写操作。事务有两种锁,并且有相应的权限。
- 读锁,也称为共享锁。某个事务A拿到该锁时,事务A只能进行读操作,此时其他事务也可以拿到这把锁(共享)。如果某个事务A拿到了读锁,其它事务可以拿到读锁(共享),但是无法获取写锁。
- 写锁,也称为排它锁。某个事务A拿到该锁时,事务A能进行读、写操作,此时其他事务不能拿到这把锁(排它)。如果某个事务A拿到了写锁,其他事务既不能拿到写锁,也拿不到读锁。
锁的粒度
所谓锁的粒度,就是锁的范围,比如如果锁的范围是一张表,则事务A获取写锁后,只能事务A进行读、写,其他事务全部要靠边站。如果锁的粒度是事务A需要操作的某几行记录,其它记录如果其他事务拿到锁仍然可以读、写。
一般情况下,锁的粒度越小(锁的范围小),则并发问题解决越好(事务都是并发执行),但是效率越低,因为需要大量的资源来确保各个事务的锁的粒度没有交集、冲突。
锁的粒度越大(锁的范围大),则并发问题解决越差(其他事务都在等待),但是效率较高,因为不要资源来控制各个事务的锁粒度交集问题。
delete和truncate在事务使用时的区别
- delete支持rollback;
- truncate 不支持rollback,直接清空表
# delete set autocommit=0; start transaction; delete from account; rollback; # truncate set autocommit=0; start transaction; truncate table account; rollback;