数据库的事务隔离级别(TRANSACTION ISOLATION LEVEL)是一个数据库上很基本的一个概念。为什么会有事务隔离级别,SQL Server上实现了哪些事务隔离级别?事务隔离级别的前提是一个多用户、多进程、多线程的并发系统,在这个系统中为了保证数据的一致性和完整性,我们引入了事务隔离级别这个概念,对一个单用户、单线程的应用来说则不存在这个问题。
事务隔离五种级别:
TRANSACTION_NONE 不使用事务。
TRANSACTION_READ_UNCOMMITTED 允许脏读。
TRANSACTION_READ_COMMITTED 防止脏读,最常用的隔离级别,并且是大多数数据库的默认隔离级别
TRANSACTION_REPEATABLE_READ 可以防止脏读和不可重复读,
TRANSACTION_SERIALIZABLE 可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的效率
以上的五个事务隔离级别都是在Connection接口中定义的静态常量,
使用setTransactionIsolation(int level) 方法可以设置事务隔离级别。
如:con.setTransactionIsolation(Connection.REPEATABLE_READ);
注意:事务的隔离级别受到数据库的限制,不同的数据库支持的的隔离级别不一定相同
首先,我们来看一下高并发的系统中会存在哪些问题,为了便于理解我们以张三在招商银行的账号和存款为例。
一、准备工作:
1. 创建一个银行账号Table(只是为了说明问题,不考虑表的设计范式)
CREATE TABLE dbo.BankAccount
(
BankAccountId CHAR(16) NOT NULL, -- 银行账号
UserName NVARCHAR(32) NOT NULL, -- 用户
Balance DECIMAL(19, 2) NOT NULL, -- 余额
LastUpdate SMALLDATETIME NOT NULL
)
GO
2. 准备数据
INSERT INTO dbo.BankAccount
VALUES ('9555500100071120', N'张三', 10000.00, GETDATE()) -- 北京分行账号
INSERT INTO dbo.BankAccount
VALUES ('9555507551227787', N'张三', 20000.00, GETDATE()) -- 深圳分行账号
GO
3. 查看数据
SELECT * FROM dbo.BankAccount
二、应用场景
假设张三在招商银行开设了两个账号,一个是招商银行北京分行,一个是招商银行深圳分行,两个账号的余额分别是10,000和20,000。
1. 张三在网上做了一笔交易,交易额100,买方小王通过银行汇款100到张三的北京分行的账号(见下面左图),柜台操作人员向张三账号存入100(事务一),然后系统些操作日志(假设需要10秒,WAITFOR DELAY '00:00:10')正在此时张三在ATM查了一下账号上余额(事务二),发现已经是10100,于是回去准备发货,但是事务一在写操作日志时超时,这是事务回滚,存款交易被取消,钱退给了小王,这样张三查到的账号余额事实上是事务一还没有提交的数据,导致张三错误的认为已经收到交易款项。
一个事务读到另外一个事务还没有提交的数据,我们称之为脏读。
解决方法:把事务隔离级别调整到READ COMMITTED,即把右上图中的SET TRAN ISOLATION LEVEL READ UNCOMMITTED更改成下图中的SET TRAN ISOLATION LEVEL READ COMMITTED。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果,因为此时事务以已经把自己的更改ROLLBACK了,所以事务二可以返回正确的结果。
再如更简单的脏读例子: e.g.
1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)
2.Mary读取自己的工资,发现自己的工资变为了8000,欢天喜地!
3.而财务发现操作有误,回滚了事务,Mary的工资又变为了1000
像这样,Mary记取的工资数8000是一个脏数据。
解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可 以避免该问题。
2. 张三先后两次查询某一账号的余额,在两次查询期间,小王完成了银行转账,导致两次的查询结果不同。
一个事务先后读取同一条记录,但两次读取的数据不同,我们称之为不可重复读。
解决方法:把事务隔离级别调整到REPEATABLE READ。在下图中使用SET TRAN ISOLATION LEVEL REPEATABLE READ。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果。
再如更简单不可重读的例子: e.g.
1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成
2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000
解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。
3. 张三妻子先后两次查询张三招商银行所有账号的总余额,而在此期间张三在广州招商银行分行成功开设了一个账号,并存入5000,导致张三妻子两次查询的总余额不同,在此期间张三原有两个账号的余额均未发生改变。
一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读。
解决方法:把事务隔离级别调整到SERIALIZABLE。在下图中使用SET TRAN ISOLATION LEVEL SERIALIZABLE。这时我们重复上面的动作会发现事务二会一直等到事务一执行完毕再返回结果。
再如更简单幻读的例子e.g.
目前工资为1000的员工有10人。
1.事务1,读取所有工资为1000的员工。
2.这时事务2向employee表插入了一条员工记录,工资也为1000
3.事务1再次读取所有工资为1000的员工 共读取到了11条记录,
解决办法:如果在操作事务完成数据处理之前,任何其他事务都不可以添加新数据,则可避免该问题。
3.1丢失更新(也属于幻像读中一种)
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。
e.g.事务A和事务B同时修改某行的值,
1.事务A将数值改为1并提交
2.事务B将数值改为2并提交。
这时数据的值为2,事务A所做的更新将会丢失。
解决办法:对行加锁,只允许并发一个更新事务。
三、总结
事务隔离级别是通过数据库的锁机制来控制的,在不同的应用场景需要应用不同的事务隔离级别,SQL Server默认的事务隔离级别是READ COMMITTED,默认的隔离级别,已经可以满足我们大部分应用的需求。
相关推荐
数据库事务的隔离级别是数据库管理系统在并发环境中保证数据一致性、避免脏读、不可重复读和幻读等问题的关键机制。在数据库领域,ACID(原子性、一致性、隔离性、持久性)理论是事务处理的基本原则。 1. **原子性...
并发控制的主要目的是防止多个事务在访问共享资源时产生不正确的数据状态,从而避免诸如丢失更新、脏读和不可重读等并发问题。 1. **数据库并发控制的含义** 并发控制是指在多用户环境下,当多个事务同时访问和...
在多用户数据库系统中,多个事务可能同时对同一数据进行读取和更新,如果没有适当的控制机制,可能会出现丢失更新、脏读和不可重读等现象。 1. **丢失更新**: 丢失更新是指两个事务对同一数据进行修改,其中一个...
Serializable(可串行化)是最严格的隔离级别,它可以防止脏读、不可重复读以及幻读。通过强制事务顺序执行,避免了并发冲突,但这可能会导致大量超时和锁竞争,影响系统性能。 在 MySQL 中,InnoDB 存储引擎通过多...
- **读未提交(READ UNCOMMITTED)**:允许读取未提交的数据,可能导致脏读、不可重复读和幻读。 - **读已提交(READ COMMITTED)**:每次读取已提交的数据,避免了脏读,但可能存在不可重复读。 - **可重读...
例如,事务T1和T2在不同的时间点读取和更新数据,可能导致更新丢失、不可重读或读取脏数据的问题。 更新丢失是指一个事务的更新被另一个事务的更新覆盖,导致原始事务的修改丢失。例如,事务T1先将X的值减去30,...
并发事务处理会带来一些问题,如更新丢失、脏读、不可重读和幻读等。更新丢失是指两个或多个事务选择同一行,然后基于最初选定的值更新该行,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题。脏读是指一...
2. 不可重读(Non-repeatable Read)/不一致分析:在事务T1读取变量A的值后,事务T2对其进行修改,然后T1再次读取时,发现值已经改变,导致事务在不同时间点看到的数据不一致。如图5所示。 3. 读脏数据(Read Dirty...
- 隔离性(Isolation):并发执行的事务之间相互独立,不会互相影响,避免诸如更新丢失、脏读、不可重读和幻读等问题。 - 持久性(Durability):一旦事务提交,其结果就是永久性的,即使系统发生故障,也能通过...
5. 并发控制是为了防止并发操作带来的数据不一致问题,如丢失更新、污读和不可重读现象。这些情况可能导致数据错误,因此并发控制通过锁定机制等策略确保数据一致性。 6. 封锁是并发控制的一种手段,分为排他锁(X...
- **Repeatable-read(可重读)**:同一事务内对相同数据的多次读取将返回相同的结果,解决了脏读和不可重复读的问题。 - **Serializable(可串行)**:确保事务以串行的方式执行,避免了所有并发问题,但可能导致更...
并发控制旨在防止多个用户同时访问同一数据块时可能出现的数据不一致,例如丢失更新、脏读和不可重读等现象。 事务是并发控制的基础,它是一个逻辑工作单元,包含一系列对数据库的操作。事务必须遵循ACID原则,即...
然而,并发执行也可能带来问题,如更新丢失、不可重读和读脏数据。 更新丢失是指在一个事务读取并修改数据后,另一个事务完成了对同一数据的修改,导致第一个事务的更新被覆盖。例如,事务T1将X的值从100减去30,而...
常见的并发控制问题包括丢失修改、脏数据和不可重读等。通过锁定机制、时间戳机制和版本机制等,可以解决并发控制问题。 数据库管理系统是指对数据库进行管理和保护的技术和方法。数据库管理系统以事务为基础,提供...
repeatable-read:可重读(幻读) 这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。 不过理论上会导致幻读(Phantom Read)。 幻读指当用户读取某一范围的数据行时,...
- Repeatable Read(默认隔离级别):可重读,避免脏读和不可重复读,但可能存在幻读。 - Serializable:可串行化,最严格的隔离级别,防止所有异常现象,但可能产生大量锁冲突和超时。 不同隔离级别的选择取决于...
13. 两段锁协议可以保证数据的可重读性。 14. 数据库中的事务可以通过锁机制来实现并发控制。 15. 数据库设计的需求分析阶段不包括建立物理数据模型的工作。 本资源摘要信息对数据库原理考试卷进行了详细分析,...
数据库原理及应用教程第3版课后题答案 数据库原理及应用教程第3版课后题答案是数据库管理系统(DBMS)领域的经典教程,涵盖了数据库...* 并发性控制:丢失更新、污读、不可重读 * 数据库恢复:登记日志文件、数据转储