事务:事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml语句要么全部成功要么全部失败。
说明:一组SQL,一个逻辑工作单位,执行整体修改或者整体回退。
事务的相关概念:
1、事务的提交和回滚:COMMIT/ROOLLBACK
2、事务的开始和结束:
开始事务:连接到数据库,执行DML,DCL,DDL语句
结束事务: 1)执行DDL(例如CREATE TABLE),DCL(例如GRANT),系统自动执行COMMIT语句
2)执行COMMIT/ROLLBACK
3)退出/断开数据库的连接自动执行COMMIT语句
4)进程意外终止,事务自动rollback
5)事务COMMIT时会生成一个唯一的系统变化号(SCN)来保存到事务表
保存点(savepoint): 可以在事务的任意位置设置保存点,以便于ROLLBACK
事务的四个特性ACID:
1)Atomicity(原子性):事务中sql语句不可分割,要么全部做,要么全部不做
2)Consistency(一致性):指事务操作前后数据库中的数据是一致的,数据满足业务规则约束(例如账户金额的转出和转入),与原子性对应
3)Isolation(隔离性):多个并发事务可以独立运行,而不能相互干扰,一个事务修改数据未提交前,其他事务不能看到它所进行的修改
4)Durability(持久性):事务提交后,数据的修改是永久的
死锁:当两个事务相互等待对方释放资源时候就会形成死锁
两个并发事务同时访问数据库表相同的行时,可能存在以下三个问题:
1、幻想读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。
2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。
3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。
为了处理这些问题,SQL标准定义了以下几种事务隔离级别
READ UNCOMMITTED 幻想读、不可重复读和脏读都允许。
READ COMMITTED 允许幻想读、不可重复读,不允许脏读
REPEATABLE READ 允许幻想读,不允许不可重复读和脏读
SERIALIZABLE 幻想读、不可重复读和脏读都不允许
事务和锁:
当执行事务操作时(dml语句),Oracle会在被作用的表上加锁,防止其他用户修改表的结构,这对我们用户来说是非常重要的
所谓死锁:是指两个或两个以上的进程在执行过程中,因为争夺资源而造成的相互等待现象,若无外力作用,这些进程都将无法进行下去
此时称系统处于死锁状态或系统产生了死锁,这些永远在相等待的进程称为死锁进程
由于资源占用是互斥的,当某个进程提出申请资源呢后,使得有关进程在无外力协助的情况下,永远分配不到资源而无法继续运行下去,就产生了这一特殊的死锁现象
数据库死锁的现象:程序执行的过程中,点击确定或者保存按钮,程序没有响应,也没提示错误
死锁的原理: 对于数据库某个表的某一列做更新或者删除操作,执行完毕后该条语句不提交,另一条对于这一列数据做更新操作的语句在执行的时候就会进入等待状态,此时的现象就是这条语句一直在执行但是一直不能执行成功,也不会报错
解决方法: 将产生死锁的语句提交即可,但是在执行的过程中,用户可能不知道产生死锁的语句是哪一句,可以将程序关闭并重新启动即可
锁包括行级锁、表级锁、悲观锁、乐观锁
行级锁:一种它锁,防止另外事务修改此行;在使用以下语句时,Oracle会自动应用行级锁:INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT];SELECT … FOR UPDATE语句允许用户一次锁定多条记录进行更新.使用commit或者rollback释放锁。 特点:开锁大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。适合于有大量按索引更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理系统。
表级锁:5种
共享锁(SHARE) - 锁定表,对记录只读不写,多个用户可以同时在同一个表上应用此锁,在表没有被任何DML操作时,多个事务都可加锁,但只有在仅一个事务加锁的情况下只有此事务才能对表更新;当表已经被更新或者指定要更新时(select for update),任何事务都不能加此锁了。
共享行排他(SHARE ROW EXCLUSIVE) – 比共享锁更多的限制,禁止使用共享锁及更高的锁,在表没有被任何DML操作时,只有一个事务可以加锁,可以更新,书上说别的事务可以使用select for update锁定选中的数据行,可是实验后没被验证。
排他(EXCLUSIVE) – 限制最强的表锁,仅允许其他用户查询该表的行。禁止修改和锁定表
行共享 (ROW SHARE) – 禁止排他锁定表,与行排他类似,区别是别的事务还可以在此表上加任何排他锁。(除排他(exclusive)外)
行排他(ROW EXCLUSIVE) – 禁止使用排他锁和共享锁,其他事务依然可以并发地对相同数据表执行查询,插入,更新,删除操作,或对表内数据行加锁的操作,但不能有其他的排他锁(自身是可以的,没发现有什么用)
悲观锁:Pessimistic Lock正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守悲观态度,事务每次去操作数据的时候都假设有其他事务会修改需要访问的数据,所以在访问之前都要求上锁,行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁,因此,在整个数据处理过程中,将数据处于锁定状态。
一个典型的倚赖数据库的悲观锁调用: select * from account where name=”Erica” for update 这条sql 语句锁定了account 表中所有符合检索条件(name=”Erica”)的记录。 本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。
乐观锁:Optimistic Lock,和悲欢锁相反,事务每次去操作数据之前,都假设其他事务不会修改这些需要访问的数据 ,所以 在访问之前不要求上锁,只是在进行更新修改操作的时候判断一下在访问的期间有没有其他人修改数据 了。它适用于多读的应用类型,冲突真的发生比较少的时候就比较好,这样省去了开销的开销,可以提高吞吐量;但如果是真的经常要发生冲突的,那每次还要去判断进行retry,反倒降低的性能,这个时候悲欢锁比较好。数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
提交事务:
当使用COMMIT语句可以提交事务,当执行了COMMIT语句后,会确认事务的变化、结束事务、删除保存节点、释放锁,当使用COMMIT语句结束事务后,其它会话将可以查看到事务变化后的新数据
回退事务:
在介绍回退事务前,先介绍一下保存点(savepoint)的概念和作用,保存点是事务中的一个点,用于取消部分事务,当结束事务时,会自动删除该事务所定义的所有保存点.当执行rollback时,通过指定保存点可以回退到指定的点.
内容参考于:https://www.cnblogs.com/lingyejun/p/7096791.html