传统隔离级别
隔离级别确定了并发用户读取或者写入的行为。读取者可以是任何选择数据的语句,默认情况下使用共享锁。写入者是任何对表进行修改的语句,并且需要一个排它锁。
SQL Server支持4个基于悲观并发控制(锁定)的传统隔离级别:READ UNCOMMITTED,READ COMMITTED, REPEATABLE READ与SERIALIZABLE。对于这4个隔离级别,隔离级别越高,读取者请求的锁就越强,并且持续时间越强。因此随着隔离级别的提高,一致性越高而并发性越低。
READ UNCOMMITTED
是可用的最低隔离级别。在该隔离级别中,读取者不需要请求共享锁。不要求共享锁的读者就不会与持有排它锁的写入者发生冲突,这意味着读取者可以读取未提交的更改(脏读)。同时也意味着读取者不会干扰排它锁的写入者,那么读取者在该隔离方式下读取数据时,写入者可以更改数据。
建立如下的连接1,并保持事务处于打开状态:
BEGIN TRAN;
UPDATE Production.Products SET unitprice += 1.00 WHERE productid = 2;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
1
2
3
4
该事务拥有产品id为2的那个产品行的排他锁;最终显示:
productid unitprice
---------- ----------
2 20.00
那么执行连接2,设置隔离级别为READ UNCOMMITTED:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
显示结果如下:
productid unitprice
---------- ----------
2 20.00
尽管连接1中的事务还没有提交,但是连接2却显示已经更改但未提交的数据。
READ COMMITTED
这是默认的隔离级别,该隔离级别仅允许读取者读取已经提交的更改,那么读取者必须要获得一个共享锁来防止未提交的更改。当写入者拥有一个排它锁时,读取者的共享锁将与之冲突,此时必须等待事务结束后才能获得共享锁,从而读取数据。
如果修改上面的连接2:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
那么当连接1的事务没有提交时,该查询便会阻塞。但是读取者所获得共享锁的持续时间仅在与SELECT语句读取间,而不是在整个事务中都拥有共享锁。
REPEATABLE READ
如果希望确保在同一事务中的多次读取之间没有其他事务能够修改值,那么就要使用REPEATABLE READ隔离级别。此时,读取者不仅需要一个共享锁才能够读写,而且直到事务结束都持有锁。那么其它事务中任何尝试获得排它锁的写操作将在事务未提交之前被阻塞。这样确保了数据在整个事务中的一致性。
在连接1中设置REPEATABLE READ隔离级别:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRAN;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
输出:
productid unitprice
---------- ----------
2 19.00
连接2如下:
UPDATE Production.Products SET unitprice += 1.00 WHERE productid = 2;
那么由于连接1事务未提交,连接2请求的排它锁与共享锁冲突,连接2中的update语句被阻塞。
REPEATABLE READ会造成丢失更新,比如两个事务同时读取一个值并尝试更新该值。由于在读取后双方都会保持它们的共享锁,那么对于两个事务中的任何一个更新都不会成功。从而造成死锁。
SERIALIZABLE
SERIALIZABLE这种隔离级别可以防止“幻读”。考虑这样的情况,事务锁定的行是在查询第一次运行时确定的,假如在事务进行第二次相同刷选条件下的查询时,其它事务添加了新行,而且新行位于查询筛选范围中,那么前后两次查询结果就不一致。从而产生“幻读”。将隔离级别设置为SERIALIZABLE级别,那么读取者锁定的行将包括查询筛选所限定的整个范围。这意味着读者锁定的不仅是查询筛选所限定的现有行,也包括将来的行。这样,其他事务尝试添加读取者查询筛选所限定的行将被阻塞。
连接1如下:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRAN;
SELECT productid, productname, categoryid, unitprice
FROM Production.Products WHERE categoryid = 1;
结果如下:
productid productname categoryid unitprice
---------- --------------- ---------- ----------
1 Product HHYDP 1 18.00
2 Product RECZE 1 19.00
...
76 Product JYGFE 1 18.00
连接2如下:
INSERT INTO Production.Products(productname, supplierid, categoryid, unitprice, discontinued)
VALUES('Product ABCDE', 1, 1, 20.00, 0);
连接2的插入将被阻止。
基于行版本的隔离级别
SQL Server还支持两种基于乐观并发控制(行版本控制)的隔离级别:SNAPSHOT和READ COMMITTED SNAPSHOT。
这种隔离级别被称于基于行版本或者快照的隔离级别,SQL Server 能够在tempdb中存储之前提交的行版本。读取者不请求共享锁。
SNAPSHOT
在SNAPSHOT隔离级别下,读取者在读取数据时,它将确保获得事务启动时最近提交的可用行版本。这意味着,保证获得的是提交后的读取并且可以重复读取,以及确保获得的不是幻读。要允许事务可以以SNAPSHOT隔离级别工作,首先要在数据库级别允许此选项:
ALTER DATABASE dbname SET ALLOW_SNAPSHOT_ISOLATION ON;
在连接1中,我们运行READ COMMITTED隔离级别,更新产品2的价格,从19.00变为20.00:
BEGIN TRAN;
UPDATE Production.Products SET unitprice += 1.00 WHERE productid = 2;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
结果显示:
productid unitprice
---------- ----------
2 20.00
连接2设置SNAPSHOT隔离级别:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
结果显示事务运行时可用的上次提交的行版本:
productid unitprice
---------- ----------
2 19.00
回到连接1,提交事务:
COMMIT TRAN;
提交事务后,价格为20.00的当期版本就变成了最新的提交版本。
在连接2中再次读取数据,并提交,此时显示的仍是19.00,因为事务还未提交,事务所保存的快照并不会发生改变:
productid unitprice
---------- ----------
2 19.00
在连接2中我们重新打开一个事务:
BEGIN TRAN;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
COMMIT TRAN;
此时事务运行时的数据快照为20.00,故显示:
productid unitprice
---------- ----------
2 20.00
对于旧的快照版本,如果没有事务使用它们,那么清理线程会及时清除它们。
SNAPSHOT隔离级别不会产生死锁,但是可以防止更新冲突。通过储存的版本可以检测更新冲突,如果在一个事务的读取与写入之间另外一个事务修改了数据,那么这个事务将会失败。
加入连接1首先进行读数据:
BEGIN TRAN;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
在连接2中更新数据:
BEGIN TRAN;
UPDATE Production.Products SET unitprice += 1.00 WHERE productid = 2;
COMMIT TRAN;
那么在连接1中重新更新数据,并提交事务:
UPDATE Production.Products SET unitprice = 21.00 WHERE productid = 2;
COMMIT TRAN;
那么这个事务会提交失败,因为检测到了更新冲突。错误信息如下:
消息 3960,级别 16,状态 2,第 1 行
快照隔离事务由于更新冲突而中止。您无法在数据库'AdventureWorks2012'中使用快照隔离来直接或间接访问表 'Production.Products',以便更新、删除或插入已由其他事务修改或删除的行。请重试该事务或更改 update/delete 语句的隔离级别。
READ COMMITED SNAPSHOT
READ COMMITED SNAPSHOT也是基于行版本控制的。但是它与SANPSHOT不同的是,读取者获得的是“语句”启动时可用的最后提交的行版本,而不是事务启动时可用的最后提交的行版本。这种隔离级别不会检测更新冲突,但是如果所请求资源以排它锁方式锁定时,它不会请求共享锁并且不会等待。
首先修改数据库设置,将READ COMMITED SNAPSHOT隔离级别打开:
ALTER DATABASE dbname SET READ_COMMITED_SNAPSHOT ON;
启动之后,隔离级别将隐式地更改为READ COMMITED SNAPSHOT
在连接1运行如下事务:
BEGIN TRAN;
UPDATE Production.Products SET unitprice += 1.00 WHERE productid = 2;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
1
2
3
4
运行后将得到:
productid unitprice
---------- ----------
2 20.00
在连接2中,打开一个事务并尝试读取产品2,并使事务处于打开状态:
BEGIN TRAN;
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
1
2
运行后得到最近提交的版本:
productid unitprice
---------- ----------
2 19.00
现在在连接1中提交事务:
COMMIT TRAN;
那么此时最近提交的行版本发生了变化(20.00),如果此时在连接2中再次读取产品2的数据,并提交事务:
SELECT productid, unitprice FROM Production.Products WHERE productid = 2;
COMMIT TRAN;
1
2
此时结果如下:
productid unitprice
---------- ----------
2 20.00
分享到:
相关推荐
#### 三、使用mysqldump进行数据库备份 `mysqldump`是一个强大的工具,用于备份MySQL数据库。它能够将数据库的数据和结构导出成一个SQL脚本文件,该文件可以被导入到另一个MySQL实例中,实现数据的迁移或备份。下面...
5. **备份与恢复**:备份文件如"50183 MySQL数据库原理及应用(第2版)(微课版)-教学用数据库(Mysql数据库备份文件)",提供了数据库灾难恢复的能力。通过mysqldump工具,我们可以创建数据库的完整或增量备份,并...
以上知识点详细阐述了MySQL数据库备份与恢复的基本操作、使用工具、以及各操作步骤。这些知识点对于数据库管理、维护和数据安全具有重要意义。通过本次实验,学生可以熟练掌握数据库的备份与恢复技能,了解不同备份...
数据库备份与还原是IT行业中非常重要的环节,尤其是在企业级应用中,数据的安全性和一致性是系统稳定运行的关键。这里我们讨论的“数据库备份及还原Java源码”是一个基于Swing开发的客户端程序,专用于MySQL数据库的...
- 使用`mysqldump`工具执行数据库备份,生成gzip压缩的SQL文件。 - 将备份文件打包成tar.gz格式。 - 删除指定天数(例如10天)前的旧备份。 - 输出备份成功的提示。 为了使脚本可执行,需通过`chmod u+x sqlAutoBak...
通常,数据库备份会按照全量备份和增量备份来进行。全量备份就是完全复制数据库的所有内容,而增量备份则只备份自上次备份以来发生更改的部分。`mysqldump`可以结合shell脚本实现自动备份,例如,每天或每周执行一次...
#### 一、数据库备份的重要性 数据库备份是数据库管理中的一个重要环节,旨在保护数据安全,防止数据丢失。通过定期备份,可以在遇到意外情况(如硬件故障、软件错误或人为误操作等)时,快速恢复数据至备份时的状态...
总结起来,数据库备份机制策略涉及到备份类型、备份策略、工具选择、执行时机、存储管理和备份验证等多个方面。理解并合理应用这些知识点,能确保企业的数据安全,提高系统的抗风险能力。在实际操作中,应根据业务...
在这个5.6.12版本中,我们可以利用它进行远程数据库备份,这对于数据库管理和维护至关重要。下面将详细介绍如何通过CMD(命令提示符)和Java来使用mysqldump进行MySQL数据库的备份。 ### CMD备份 在Windows系统中...
Java命令行工具在数据库备份中的应用通常涉及以下步骤: 1. **连接数据库**:使用JDBC驱动建立与数据库的连接,获取必要的权限。 2. **执行备份脚本**:编写SQL备份脚本,或者调用数据库管理系统提供的备份命令...
### 数据库备份与还原知识点详解 #### 一、引言 在现代信息技术中,数据的安全性和完整性至关重要。数据库作为存储和管理数据的核心工具,在企业运营和个人应用中扮演着不可或缺的角色。然而,由于硬件故障、软件...
数据库备份与还原是保障数据安全的重要手段,防止因系统故障、人为错误或恶意攻击导致的数据丢失。本项目聚焦于MySQL数据库的备份和还原功能,同时支持分表和分卷操作,既适用于服务器环境,也适用于本地环境。接...
数据库备份是将数据库中的所有数据复制到安全的位置,以防数据丢失或损坏。而还原则是当数据库出现问题时,将备份的数据恢复到数据库中,确保数据的完整性和一致性。 在Delphi中,我们可以使用MySQL的Connector/...
3. 处理输出:将`mysqldump`的输出保存到本地文件,例如“mydb数据库备份.sql”。 4. 断开连接:使用`mysqli_close()`或`PDO::disconnect()`关闭数据库连接。 5. 错误处理:为了防止潜在的BUG,程序应该包含适当的...
数据库备份是确保数据安全的重要步骤,当系统出现故障或需要回滚到某一状态时,备份文件可以派上用场。在C#中,可以利用`mysqldump`命令来生成数据库的SQL脚本备份。在`btn_Dump_Click`事件处理函数中,首先打开一个...
整体数据库备份是指将整个数据库中的所有表和数据保存到一个文件中。这通常通过执行SQL语句`mysqldump`来完成。在PHP中,可以使用`shell_exec()`或`exec()`函数调用系统命令来执行`mysqldump`。以下是一个简单的示例...
使用`mysqldump`备份数据库(完全+增量备份,适合中型数据库备份) 对于中型规模的数据库而言,`mysqldump`是一个更优的选择。它不仅可以实现完全备份,还能进行增量备份。使用`mysqldump`进行备份时,可以根据需要...
在IT领域,数据库备份是确保数据安全性和业务连续性的重要环节。C#是一种广泛用于开发Windows应用程序的编程语言,而WinFrom则是C#中的一个GUI(图形用户界面)框架,常用于构建桌面应用。本篇将详细介绍如何使用C# ...
总结来说,MySQL数据库备份是多方面的,涉及选择合适的备份策略、理解不同备份方法的优缺点,以及在恢复过程中的最佳实践。无论选择哪种方式,定期备份、日志记录和妥善存储备份文件都是确保数据安全的关键步骤。
本篇将详细介绍由C#编写的MYSQL数据库备份恢复工具,以及其中涉及的关键技术和实现方式。 首先,C#是一种面向对象的编程语言,由微软公司推出,它具有丰富的类库和强大的.NET框架支持,适用于开发Windows桌面应用、...