数据库语言——TCL语言


事务

一、含义

事务:一条或一组sql语句组成一个执行单位,一组sql语句要么都执行要么都不执行。如果其中有一条发生错误,整个单元就要回滚,即所有受影响的数据将要被恢复。(transaction - 事务)
解释:就比如转账的例子,A向B转账。A,B原来月都为1000,我们可以把转账分为两步。A账户更新,B账户也要更新。这两条sql语句组成一个事务,这两个要么同时都发生,要么都不发生。

二、特点(ACID)

原子性(Atomicity):一个事务是不可再分割的整体,要么都执行要么都不执行
一致性(Consistency):一个事务可以使数据从一个一致状态切换到另外一个一致的状态。就比如上面说的转账,A和B的总金额是不变的。
隔离性(Isolation):一个事务不受其他事务的干扰,多个事务互相隔离的。并发执行的多个事务之间不能互相干扰。
持久性(Durability):一个事务一旦提交了,则永久的持久化到本地。

三、事务的使用步骤 ★

隐式(自动)事务:没有明显的开启和结束,本身就是一条事务可以自动提交,比如insert、update、delete
显式事务:具有明显的开启和结束。
就比如说我们想要更新转账的记录,至少需要两条语句,那么我们就需要使用显式事务。

1. 使用显式事务:

步骤①:开启事务

set autocommit=0;    # 这句就已经默认开启事务了,下面的可以不写
start transaction;   #可以省略

步骤②:编写一组逻辑sql语句
注意:sql语句支持的是select、insert、update、delete

语句1;
语句2;
...

步骤③:结束事务

提交:commit;
回滚:rollback;   # 回到没有执行sql语句的最初状态
回滚到指定的地方:rollback to 回滚点名;
# 要么提交,要么回滚

由此可见,事务的执行是先将数据保存到内存中,等事务结束之后再写进磁盘。
我们来看一个例子:

# 最初的状态为A 1000,B 1000;
#开启事务
SET autocommit=0;
# 设置一组sql语句作为一个事务
UPDATE u_account SET money = 500 WHERE u_name = 'A';
UPDATE u_account SET money = 1500 WHERE u_name = 'B';
# 结束事务或者执行回滚
COMMIT;
#rollback;  如果不执行commit,而是执行rollback,那么数据还是都是1000,不尽兴更新。

四、并发事务

1、事务的并发问题是如何发生的?

多个事务 同时 操作 同一个数据库的相同数据时

2、并发问题都有哪些?

脏读:一个事务读取了其他事务还没有提交的数据,读到的是其他事务“更新”的数据。就比如说对于两个事务T1,T2。T1读取了已经被T2更新但还没有提交的数据,之后如果T2回滚,T1读取的内容就是临时且无效的。
不可重复读:一个事务多次读取,结果不一样。
幻读:一个事务读取了其他事务还没有提交的数据,只是读到的是其他事务“插入”的数据。(即一个事务执行读的操作,另一个事务执行插入的操作)

3、如何解决并发问题

通过设置隔离级别来解决并发问题

4、隔离级别

隔离级别描述
read uncommitted:读未提交数据允许事务读取未被其他事务提交的变更。脏读,不可重复读和幻读的问题都会出现
read commited:读已提交只允许事务读取已经被其他事物提交的变更。可以避免脏读,不可以避免不可重复读和幻读
repeatable read:可重复读确保事务可以多次从一个字段读取相同的值,在这个事务的持续期间,禁止其他事物对这个字段进行修改。可以避免脏读和不可重复读,不可以避免幻读
serializable:串行化确保一个事务可以从表中读取到相同的行。在这个事务持续期间,禁止其他事务对该表执行插入,更新和删除操作。所有的并发问题都可以解决,但是性能十分低下
是否可以避免脏读不可重复读幻读
read uncommitted:读未提交×××
read committed:读已提交××
repeatable read:可重复读×
serializable:串行化

下面参考文章

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事务的并发操作中可能会出现脏读,不可重复读,幻读。下面通过事例一一阐述它们的概念与联系。


Read uncommitted

读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读


那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。


Read committed

读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读


那怎么解决可能的不可重复读问题?Repeatable read !


Repeatable read

重复读,就是在开始读取数据(事务开启)时,不再允许修改操作

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作


什么时候会出现幻读?

事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。


那怎么解决幻读问题?Serializable!


Serializable 序列化

Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。


值得一提的是:大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值