- 数据库 - 事务 transaction


>> 什么是事务

产生事务就会产生锁;

~MySQL

MySQL中,事务是一个最小的不可分割的工作单元,事务里面可以包含多条SQL语句,事务中的语句,要么全部执行成功,事务提交,要么有一条语句执行失败,事务回滚到开始事务之前的状态;事务能保证业务的完整性

MySQL中是默认开启事务(自动提交)的,也就是说,如果不显示的开始一个事务,每个语句都会被当做一个事务执行提交操作;
所以当我们去执行一条sql语句时,效果会立即体现出来,不能回滚;这时如果执行两个语句,第一个执行成功了,第二个执行失败,我们不能回滚操作,这就会出现数据不一致问题;

我们可以手动开启一个事务,然后再执行多条语句,若其中一条执行失败,可以执行回滚操作;若都执行成功,可以commit提交;这时候事务就结束了,就不能再回滚了;

  • 事务开启
    1、修改默认提交:set autocommit=0;
    2、begin;
    3、start transaction;
  • 事务提交commit;,将修改的数据持久保留;
  • 事务回滚rollback;,撤销语句的执行效果;

~ Oracle

查看事务:select * from v$transaction;

事务采用隐性的方式,起始于session的第一条DML语句;
事务结束于:
(1)commit或rollback;
(2)DDL语句被执行(提交);
(3)DCL语句被执行(提交);
(4)用户退出SQLplus:正常退出是提交,非正常退出是回滚;
(5)机器故障或系统崩溃(回滚);
(6)shutdown immediate(回滚);

DML:insert、update、delete、merge;
DDL:create、alter、drop、truncate;
DCL:grant、revoke;


>> 事务的四大特征 - ACID

1、原子性(Acomicity ):一个事务必须被视为一个不可分割的最小的工作单元,整个事务中的所有操作,要么全部执行成功提交,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作;这就是事务的原子性;

场景: 银行转账,A-100,B+100,同时成功或同时失败;

2、一致性(Consistency)
解释1:数据库总是从一个一致性状态 转换到另一个一致性状态;比如从A账户转账给B账户,不管操作是否成功,两个账户的存款总额不变;
解释2:一个查询的结果,必须与数据库在查询开始时的状态一致;(读不等待写,写不等待读)

场景: 用户A查询某个表的数据时,九点开始,此时表中有100万条记录,需要查询十分钟,九点五分的时候,用户B向表中插入了一条数据,此时表中有100万零1条记录,但是用户A查询出来的还是100万条记录;就是说查询操作开始执行时,表中有多少条记录,查询出来的就有多少条;

3、隔离性(Isolation):通常来说,事务之间互不干扰;一个事务所做的修改在最终提交之前,对其他事务是不可见的;隔离的程度通过设置隔离级别来确定;

场景: 两个session,一个查询,一个更新,更新的操作没有提交之前,查询所看到的数据都是没有更新之前的,两个session互不影响;

4、持久性(Driability):事务一旦结束(commit),其所做的修改就会永久保存到数据库中,就不可再回滚;数据库通过日志能够保证事务的持久性;

场景: 事务提交之后是不可逆的,提交数据是将内存的数据刷新到硬盘上,Oracle靠“rudo”日志实现;事务提交时,rudo会先将提交的操作记录到日志文件中,然后才开始往磁盘刷数据的操作,比如批量insert,执行到一半的时候,操作中断了,Oracle重启恢复之后,会从rudo中找到日志,继续未完成的事;


>> 锁 (oracle)

1、锁的用途: 只有有事务才有锁,用于保证数据的完整性和一致性;

2、锁的分类:

  • 共享锁:排斥其他锁,不排斥共享锁;
  • 排他锁:独占,排斥其他共享锁、排它锁;

3、锁的类型:

  • DML锁:data locks,数据锁,用于保护数据的完整性;
    TX:行级锁;
    TM:表级锁;
  • DDL锁:dictionary locks,数据字典锁,用于保护数据库对象的结构,如表、索引等的结构定义;
  • system锁:internal locks and latches,保护数据库的内部结构;

4、加锁模式:
在做DML (insert/update/delete)时自动加锁,使用select ... for update加锁;

A用户select * from user where username = 'zxj' for update;执行时这条记录会被锁定;这时用户B要update这条记录,就会进入等到状态,等A提交释放锁之后,就会立即执行B的update操作;

Oracle里面不存在死锁,有的话Oracle会自动解决; 若是A一直不释放锁,B将一直处于等待状态,若B的操作是点击页面的更改按钮,就会出现页面一直刷不出来,会被认为出现死锁,不友好;

解决这个问题的方案:
(1)select * from user where username = 'zxj' for update nowait;,不等待,B执行操作,会立即返回提示信息:资源正忙…
(2)select * from user where username = 'zxj' for update wait 5;,等待5秒,5秒之后,返回提示信息:资源被占用…
(3)select * from user where username = 'zxj' for update skip locked;,跳过被锁定的记录,返回其他没有锁定的记录;

5、暴力解锁:select ... for update的锁占用的时间太长,可以通过管理员用户kill掉创建锁的session;
(1)查看v$lock表,查看哪个sid占用的时间长;
(2)根据查出来的sid,去v$session表中查找session:select sid, serial# from v$sesssion where sid = ...;
(3)alter system kill session 'sid的值, serial#的值';


>> 事务隔离级别

和Java程序使用对象锁机制进行线程同步类似,数据库管理系统采用数据库锁机制保证事务的隔离性;当多个事务试图对相同数据进行操作时,只有持有锁的事务才能操作数据,知道一个事务提交之后,其他事务才有机会对数据进行操作;

事务隔离级别是数据库提供的自动锁机制;

查看事务隔离级别:

mysql 8.x:
	select @@global.transaction_isolation;  系统级别的;
	select @@transaction_isolation;         会话级别的;
mysql 5.x:
	select @@global.tx_isolation;  系统级别的;
	select @@tx_isolation;         会话级别的;

修改事务隔离级别:

set global transation isolaction level read uncommitted;

事务的隔离级别:

  • read uncommitted:读未提交;
  • read committed:读已提交;
  • repeatable read:可重复读;MySQL默认级别
  • serializable:串行化;

较低级别的隔离,通常可以执行更高的并发,系统的开销也更低;事务隔离级别越高,数据库性能越差:serializable级别最高,并发最低,性能最差;


1、read uncommitted:读未提交 - 脏读

事务中的修改,即使没有提交,修改的数据对其他事务也是可见的;

脏读:一个事务读取到了另一个事务B修改未提交的数据;

如果事务A读取到了事务B修改未提交的更改数据,并在这个数据的基础上进行操作,若这时事务B回滚,那么事务A读取到的数据是不被承认的;

2、read committed:读已提交 - 不可重复读

一个事务从开始直到提交之前,所做的修改对其他事务都不可见;一个事务只能读取到另一个事务已经提交的更改数据

但是会出现不可重复读现象:执行两次同样的查询操作,可能会得到不一样的结果;

事务A查询账户余额为100,这时事务B取出10元,将余额改为90元,提交事务,然后事务A再次读取账户余额,两次读取到的数据不一样;

3、repeatable read:可重复读 - 幻象读

该级别保证了同一个事务中,多次读取同样的记录的结果是一样的;
但是在统计数据的事务中,可能发生幻象读;

幻象读:一个事务A读取不到另一个事务B新增的并已经提价的记录,但是新纪录又会影响到事务A的操作;

(1)事务A查询表中有5条记录,这时事务B向表中插入一条记录,并提交,事务A再次查询记录数还是5条,这时事务A向表中插入同样一条记录,会报错:显示该记录以存在,这就出现了幻象读;
(2)事务A统计所有账户总额是100,这时事务B新增账户,余额是1,然后提交,账户A再次统计余额时是101,幻象读;

不可重复读指的是读到了其他事务已经提交的更改或删除的数据;
幻象读指的是读取到了其他事务已提交的新增数据;

4、serializable:串行化;

一个事务A操作一个表的时候,其他事务B不能对该表执行写操作,其他事务B会进入串行化状态(排队),等待事务A操作完提交之后,事务B的写操作会自动执行;(没有超时的情况下)


>> 数据库并发的问题

  • 脏读:事务A读取到了事务B未提交的数据,使用之后,事务B执行回滚操作,使得事务A读取到的数据失效;

  • 不可重复读:事务A读取到了事务B修改或删除的数据,使得事务A在事务B的操作执行前后两次相同的读取操作,读取到的数据不一致;

  • 幻象读:事务A读取不到事务B已经提交的新增数据,但是新增数据又会影响事务A的操作;

  • 第一类丢失更新:事务A回滚事务时,覆盖事务B已提交的数据;
    事务A开启事务,查询账户余额为1000,事务B开启事务,查询余额1000,然后存入100将余额改为1100,并提交,事务A取出100,将余额改为900,操作失败,事务A回滚,余额恢复为1000;这时事务B存入的100元丢失;

  • 第二类丢失更新:事务A提交事务时,覆盖事务B已经提交的数据;
    事务A查询余额1000,事务B查询余额为1000,取出100,余额改为900,提交事务;事务A存入100,提交事务,余额改为1100;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值