当前位置: 首页 > 知识库问答 >
问题:

不同隔离级别的数据库事务的动态冲突

魏硕
2023-03-14

我对交易和隔离级别有一些疑问:

1) 如果DB事务级别设置为Serializable/RepeatableRead,并且有两个并发事务试图修改同一数据,则其中一个事务将失败。

在这种情况下,为什么DB不重试失败的操作?在应用程序级别重试事务是否是一个好的做法(希望另一个事务将在同一时间结束)?

2)如果数据库事务级别设置为READ_COMMITTED/DIRTY READ,并且有两个并发事务试图修改相同的数据,那么为什么事务不会失败?

理想情况下,我们控制读取行为,不允许并发写入。

3)我的应用程序有2个部分,一部分使用spring托管数据源,另一部分使用应用程序创建的数据源(这部分不使用spring,数据源是通过传递属性显式创建的)。

我的假设是隔离级别没有影响 - 连接来自哪个数据源......两个并发事务即使来自不同数据源,根据隔离级别的行为也与来自同一数据源相同。

您认为这种设置有什么问题吗?我们应该争取跨应用程序的单一数据源吗?

共有1个答案

谷梁存
2023-03-14

我也等到别人反馈。但是现在我想把我的2美分给这个帖子。正如您所解释的,隔离的工作方式各不相同。

我将尝试保留一个示例数据集,如下所示

IF OBJECT_ID('Employees') IS NOT NULL DROP TABLE Employees
GO

CREATE TABLE Employees (
    Emp_id INT IDENTITY,
    Emp_name VARCHAR(20),
    Emp_Telephone VARCHAR(15),
)

ALTER TABLE Employees
ADD CONSTRAINT PK_Employees PRIMARY KEY (emp_id)


INSERT INTO Employees (Emp_name, Emp_Telephone)
    SELECT 'Satsara', '07436743439'
INSERT INTO Employees (Emp_name, Emp_Telephone)
    SELECT 'Udhara', '045672903'
INSERT INTO Employees (Emp_name, Emp_Telephone)
    SELECT 'Sithara', '58745874859'

可重复读取和串行化都非常接近,但串行化是隔离的高度。这两个选项都是为了避免脏读数而提供的,并且都需要非常小心地管理,因为大多数情况下,由于处理数据的方式,这会导致死锁。如果出现死锁,服务器肯定会从图片中清除一个事务。因此,它不会再由服务器运行它,因为它没有关于被删除的事务的任何线索,除非有日志

可重复读取-不允许修改(锁定记录)任何已被另一个进程(另一个查询)读取的记录。但是它允许插入新记录(没有锁),这可能会在查询时影响您的系统。

SERIALIZABLE-SERIALIZABLE不同,它不允许插入带有
“SET TRANSACTION ISOLATION LEVEL Serializaable”的记录。因此,INSERT处理器将一直等到上一个事务提交。

通常,可重复读取和可序列化隔离是保持数据锁,而不是其他两个选项。

示例[可重复和可序列化]:

在“员工”表中,您有 3 条记录。

    < li >打开查询窗口并运行(查询1)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRAN
SELECT * FROM Employees;
INSERT INTO Employees(Emp_name, Emp_Telephone)
    SELECT 'JANAKA', '3333333'

系统允许在查询2中插入新记录,现在再次运行相同的查询2,您可以看到4条记录。

现在将Query1替换为以下代码,并尝试相同的过程来测试Serializable

SET TRANSACTION ISOLATION LEVEL Serializable
BEGIN TRAN
SELECT * FROM Employees;

这一次,您可以看到第二个查询插入命令不允许执行,并等待查询 1 提交。

仅提交查询1后,查询2允许执行INSERT命令。

比较已提交的读取和未提交的读取时,

READ COMMITTED-在提交记录之前,对数据的更改对其他处理器不可见。使用读取委员会。它为它读取的所有记录放置共享锁。如果另一个进程发现了独占锁,它会等待直到它的锁释放。

读取未提交 - 不建议使用,因此系统可以读取垃圾数据。(在 SQL Server nolock 中)。因此,这将返回未提交的数据。“从员工(无锁)中选择 *”

**死锁 - ** 无论是可重复读取、可序列化、已提交读取还是未提交读取,它都可能创建死锁。唯一的事情是我们讨论的可重复读取和可序列化比其他两个选项更容易出现死锁。

注意:如果您需要已提交读取和未提交读取的示例,请在评论部分告知,我们可以讨论。

事实上,这个话题是一个很大的话题,需要用很多样本来讨论。我不知道这个解释是否足够。但是我试了一下。没有想法可以开始,什么时候停止。

同时,您询问“在应用程序级别重试事务是一种好的做法吗”

在我看来,这很好。就我个人而言,我也在某种情况下重试过程。使用了不同的技术。

  1. 保留标志字段以标识其是否更新并重试
  2. 使用事件驱动的解决方案,如RabitMQ,KAFKA。
 类似资料:
  • 主要内容:事务概述,事务的四大特性,并发事务问题,事务的隔离级别,演示:,总结事务概述 事务是一个或一组sql语句组成的一个执行单元,这个执行单元要么全部执行成功,要么全部执行失败。用于保证数据的完整性。 如账户转账,张三给李四转500,对应的sql语句应该是update张三的 余额-500,并且update李四的余额+500,如果先更新完张三的数据,然后出现了异常,导致李四的余额修改不了,那么就出现数据上的问题了,应该使用事务来解决这一问题,当中间出现异常后回滚,让张三的

  • 研究隔离级别和阻塞,更具体的读提交与读提交快照。 在SQL Server 2014中,默认隔离级别是提交读取,如果我运行 然后在新的连接中 第二个查询将阻塞并挂起。 然而,在Azure SQL中,隔离级别是READ COMMITTED SNAPSHOT,它似乎允许从Person读取。持TABLOCKX的人在等待。 问:如何重现阻塞场景,可能有提示,强制第一个SELECT完全阻塞表,同时打开READ

  • 我将spring应用程序连接到smartbaer servicev,在那里创建了虚拟数据源(Postgres)。 驱动程序类: 连接字符串(本地servicev虚拟服务器url): 应用程序.属性:- spring.datasource.driver-class-name=com.smartbear.servicev.jdbc.driver.jdbcvirtdriver spring.dataso

  • 本文向大家介绍事务的隔离级别有哪些?相关面试题,主要包含被问及事务的隔离级别有哪些?时的应答技巧和注意事项,需要的朋友参考一下 SQL 标准定义了四个隔离级别: READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重

  • 问题内容: 我正在编写一个小小的拍卖应用程序,因此务必要确定我的出价,这一点非常重要。毕竟,拍卖的最后几秒钟对买家来说是关键时刻,我不能冒险让他们同时竞标和拥有比赛条件。 当然,这就是事务隔离的目的。我可以将隔离级别设置为可序列化,并且一切就绪。 但是其他所有请求呢?如果人们正在查看个人资料或发送消息,则这些请求不需要这种事务隔离。对于这些请求,完全可以接受读取的提交隔离级别。 我将事务级别设置为

  • 本文向大家介绍说一下数据库的事务隔离?相关面试题,主要包含被问及说一下数据库的事务隔离?时的应答技巧和注意事项,需要的朋友参考一下 MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加: transaction-isolation = REPEATABLE-READ 1 可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABL