SQL事务与脏读、幻读总结

本文详细介绍了数据库事务的概念及其四大特性:原子性、一致性、隔离性和持久性。并举例说明了事务在实际应用场景中的重要性,以及脏读、不可重复读和幻读等概念。

总结一下

事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。

事务有四个特性:
1、原子性。即不可分割性,事务要么全部被执行,要么就全部不被执行。如果事务的所有子事务全部提交成功,则所有的数据库操作被提交,数据库状态发生转换;如果有子事务失败,则其他子事务的数据库操作被回滚,即数据库回到事务执行前的状态,不会发生状态转换。
2、 一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态。
3、隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,即在事务正确提交之前,它可能的结果不应显示给任何其他事务。
4、持久性。事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。

事务处理是数据库中很重要的一部分,如果一个数据库不支持事务处理,会导致原来用事务处理很简单的方案变得复杂,对于交易系统等是一定要有事务处理支持的。例如客户做一笔转账,需要从转出账户扣掉一笔钱,在转入账户增加一笔钱。这两个动作要么都成功,要么都失败,用事务处理很容易实现。对于没有事务处理的数据库,你可以考虑一下要怎么处理,一定很复杂把

而数据库有无事务的区别是:

事务处理的引入是为了解决操作的原子性,正如fita所提到的转帐中的动作,如果后一个动作失败,可以通过事务回滚(rollback)回到事务开始的状态。
事务和无事务各有优缺点
有事务:安全,可一次提交多个操作,可回滚,可恢复
无事务:高速,节省磁盘空间,操作节省内存
现行的大多数主流数据库系统支持事务处理。

脏读,不可重复读
注:脏读的后果很严重。
脏读意味着一个事务读取了另一个事务未提交的数据,这个数据是有可能回滚的;一个事务读到另一个事务,尚未提交的修改,就是脏读。这里所谓的修改,除了Update操作,不要忘了,还包括Insert和Delete操作。脏读的后果:如果后一个事务回滚,那么它所做的修改,统统都会被撤销。前一个事务读到的数据,就是垃圾数据。

举个例子:

预订房间。 有一张Reservation表,往表中插入一条记录,来订购一个房间。
事务1:在Reservation表中插入一条记录,用于预订99号房间。
事务2:查询,尚未预定的房间列表,因为99号房间,已经被事务1预订。所以不在列表中。 事务1:信用卡付款。由于付款失败,导致整个事务回滚。
所以插入到Reservation 表中的记录并不置为持久(即它将被删除)。 现在99号房间则为可用。 所以,事务2所用的是一个无效的房间列表,因为99号房间,已经可用。如果它是最后一个没有被预定的房间,那么这将是一个严重的失误。

不可重复读意味着在数据库访问中,一个事务范围两个相同的查询却返回了不同数据,这是由于系统中其他事务的修改而引起的; 

事务b( select操作)中对某个查询执行两次,当第一次执行完时,事务a对其数据进行了修改。事务b再次查询时,数据发生了改变;
事务1:查询有双人床房间。99号房间,有双人床。 事务2:将99号房间,改成单人床房间。 事务1:再次执行查询,请求所有双人床房间列表,99号房间不再列表中了。也就是说, 事务1,可以看到其他事务所做的修改。 在不可重复读,里面,可以看到其他事务所做的修改,而导致2次的查询结果不再一样了。 这里的修改,是提交过的。也可以是没有提交的,这种情况同时也是脏读。

幻读:是指当事务还是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到了表中的全部数据行。同时,第二个事务也 修改这个表中的数据,这种修改是向表中插入一行新数据。所以,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

事务1读取指定的where子句所返回的一些行。然后,事务2插入一个新行,这个新行也满足事务1使用的查询
where子句。然后事务1再次使用相同的查询读取行,但是现在它看到了事务2刚插入的行。这个行被称为幻象,
因为对事务1来说,这一行的出现是不可思议的。
举个例子:

事务1:请求没有预定的,双人床房间列表。 事务2:向Reservation表中插入一个新纪录,以预订99号房间,并提交。
事务1:再次请求有双人床的未预定的房间列表,99号房间,不再位于列表中。

最后:
不可重复读的重点是修改:
幻读的重点在于新增或者删除

### 的定义及其解决方案 #### 什么是是指在一个事务取到了另一个尚未提交事务修改过的数据。这种现象通常发生在较低的隔离级别(如 **未提交**)下,此时事务能够看到其他事务还未完成的操作结果。为了防止的发生,可以通过提高隔离级别来实现。例如,在 **可重复 (Repeatable Read)** 或者 **串行化 (Serializable)** 的隔离级别下,事务只能取到已经提交的数据[^1]。 #### 如何解决? - 提高数据库事务隔离级别至 **已提交 (Read Committed)** 或更高。 - 使用 MVCC(多版本并发控制),允许事务取的是历史版本的数据而不是最新的未提交版本[^2]。 --- #### 什么是指的是在同一事务中,两次执行相同的查询语句却返回了不同的结果集。具体表现为第一次查询某范围内的记录数为 N 条,但在第二次查询同一范围内时却发现出现了新的记录或者某些记录被删除的情况。这通常是由于其他事务在此期间插入或删除了该范围内的数据所引起的。 对于基于快照的操作来说,MVCC 技术确实能有效避免大部分类型的;然而当涉及到当前(如 `SELECT ... FOR UPDATE`、`UPDATE` 和 `DELETE` 等操作)时,则仍然可能出现问题[^3]。 #### 如何解决? 以下是几种常用的解决方案: 1. **加锁机制**: 对于可能发生的关键区域采用显式的锁定策略,比如使用间隙锁(Gap Locks)。这样可以阻止其他事务向这些特定区间内插入新纪录直到当前持有锁的那个事务结束并释放其占用资源为止[^4]。 ```sql -- 示例:通过 SELECT...FOR UPDATE 实现当前并施加行级锁 BEGIN; SELECT * FROM table_name WHERE id BETWEEN 1 AND 10 FOR UPDATE; COMMIT; ``` 2. **提升隔离级别**: 将事务运行环境调整成更高的隔离等级——即达到“可重复”甚至完全独占模式下的“序列化”。不过需要注意这样做可能会带来额外开销以及降低系统的整体吞吐量。 3. **应用层逻辑优化**: 如果业务场景允许的话也可以考虑从业务流程设计上去规避此类冲突情况的发生, 比如减少不必要的频繁更新动作或是合理规划好每次批量处理的数量大小等等. --- ### 总结表:不同隔离级别对问题的影响 | 隔离级别 | 是否允许 | 是否允许不可重复 | 是否允许 | |------------------|---------------|--------------------|----------------| | 未提交 | 是 | 是 | 是 | | 已提交 | 否 | 是 | 是 | | 可重复 | 否 | 否 | 是(仅限当前) | | 序列化 | 否 | 否 | 否 | --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值